From 84e9264e76ca6e5d984c8eecbf5c5d11128fc174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 24 Apr 2025 08:29:08 +0000 Subject: [PATCH 001/118] 8346552: C2: Add IR tests to check that Predicate cloning in Loop Unswitching works as expected Co-authored-by: Christian Hagedorn Reviewed-by: chagedorn, epeter --- src/hotspot/share/opto/ifnode.cpp | 4 +- src/hotspot/share/opto/predicates.cpp | 13 +- src/hotspot/share/opto/predicates.hpp | 1 + .../compiler/lib/ir_framework/IRNode.java | 28 ++- .../TestUnswitchPredicateCloning.java | 183 ++++++++++++++++++ 5 files changed, 221 insertions(+), 8 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestUnswitchPredicateCloning.java diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 5d349caf103..8d810e4202f 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -2219,13 +2219,13 @@ void ParsePredicateNode::dump_spec(outputStream* st) const { st->print("Loop "); break; case Deoptimization::DeoptReason::Reason_profile_predicate: - st->print("Profiled Loop "); + st->print("Profiled_Loop "); break; case Deoptimization::DeoptReason::Reason_auto_vectorization_check: st->print("Auto_Vectorization_Check "); break; case Deoptimization::DeoptReason::Reason_loop_limit_check: - st->print("Loop Limit Check "); + st->print("Loop_Limit_Check "); break; default: fatal("unknown kind"); diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index 90df1ff05b4..78061801e6a 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -29,6 +29,7 @@ #include "opto/node.hpp" #include "opto/predicates.hpp" #include "opto/rootnode.hpp" +#include "runtime/deoptimization.hpp" // Walk over all Initialized Assertion Predicates and return the entry into the first Initialized Assertion Predicate // (i.e. not belonging to an Initialized Assertion Predicate anymore) @@ -1093,11 +1094,19 @@ CloneUnswitchedLoopPredicatesVisitor::CloneUnswitchedLoopPredicatesVisitor( PhaseIdealLoop* phase) : _clone_predicate_to_true_path_loop(true_path_loop_head, node_in_true_path_loop_body, phase), _clone_predicate_to_false_path_loop(false_path_loop_head, node_in_false_path_loop_body, phase), - _phase(phase) {} + _phase(phase), + _is_counted_loop(true_path_loop_head->is_CountedLoop()) {} -// Keep track of whether we are in the correct Predicate Block where Template Assertion Predicates can be found. // The PredicateIterator will always start at the loop entry and first visits the Loop Limit Check Predicate Block. +// Does not clone a Loop Limit Check Parse Predicate if a counted loop is unswitched, because it most likely will not be +// used anymore (it could only be used when both unswitched loop versions die and the Loop Limit Check Parse Predicate +// ends up at a LoopNode without Loop Limit Check Parse Predicate directly following the unswitched loop that can then +// be speculatively converted to a counted loop - this is rather rare). void CloneUnswitchedLoopPredicatesVisitor::visit(const ParsePredicate& parse_predicate) { + Deoptimization::DeoptReason deopt_reason = parse_predicate.head()->deopt_reason(); + if (_is_counted_loop && deopt_reason == Deoptimization::Reason_loop_limit_check) { + return; + } _clone_predicate_to_true_path_loop.clone_parse_predicate(parse_predicate, false); _clone_predicate_to_false_path_loop.clone_parse_predicate(parse_predicate, true); parse_predicate.kill(_phase->igvn()); diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index 5cea5598392..f19b2d73c56 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -1176,6 +1176,7 @@ class CloneUnswitchedLoopPredicatesVisitor : public PredicateVisitor { ClonePredicateToTargetLoop _clone_predicate_to_false_path_loop; PhaseIdealLoop* const _phase; + const bool _is_counted_loop; public: CloneUnswitchedLoopPredicatesVisitor(LoopNode* true_path_loop_head, diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index e7340dd0d8f..0b224523561 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1470,6 +1470,11 @@ public class IRNode { optoOnly(OOPMAP_WITH, regex); } + public static final String OPAQUE_TEMPLATE_ASSERTION_PREDICATE = PREFIX + "OPAQUE_TEMPLATE_ASSERTION_PREDICATE" + POSTFIX; + static { + duringLoopOpts(OPAQUE_TEMPLATE_ASSERTION_PREDICATE, "OpaqueTemplateAssertionPredicate"); + } + public static final String OR_I = PREFIX + "OR_I" + POSTFIX; static { beforeMatchingNameRegex(OR_I, "OrI"); @@ -1576,12 +1581,17 @@ public class IRNode { public static final String LOOP_LIMIT_CHECK_PARSE_PREDICATE = PREFIX + "LOOP_LIMIT_CHECK_PARSE_PREDICATE" + POSTFIX; static { - parsePredicateNodes(LOOP_LIMIT_CHECK_PARSE_PREDICATE, "Loop Limit Check"); + parsePredicateNodes(LOOP_LIMIT_CHECK_PARSE_PREDICATE, "Loop_Limit_Check"); } public static final String PROFILED_LOOP_PARSE_PREDICATE = PREFIX + "PROFILED_LOOP_PARSE_PREDICATE" + POSTFIX; static { - parsePredicateNodes(PROFILED_LOOP_PARSE_PREDICATE, "Profiled Loop"); + parsePredicateNodes(PROFILED_LOOP_PARSE_PREDICATE, "Profiled_Loop"); + } + + public static final String AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE = PREFIX + "AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE" + POSTFIX; + static { + parsePredicateNodes(AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "Auto_Vectorization_Check"); } public static final String PREDICATE_TRAP = PREFIX + "PREDICATE_TRAP" + POSTFIX; @@ -2826,16 +2836,26 @@ private static void afterBarrierExpansionToBeforeMatching(String irNodePlacehold CompilePhase.BEFORE_MATCHING)); } + /** + * Apply {@code regex} on all ideal graph phases starting from {@link CompilePhase#BEFORE_LOOP_OPTS} + * up to and including {@link CompilePhase#AFTER_LOOP_OPTS}. + */ + private static void duringLoopOpts(String irNodePlaceholder, String regex) { + IR_NODE_MAPPINGS.put(irNodePlaceholder, new SinglePhaseRangeEntry(CompilePhase.AFTER_LOOP_OPTS, regex, + CompilePhase.BEFORE_LOOP_OPTS, + CompilePhase.AFTER_LOOP_OPTS)); + } + private static void trapNodes(String irNodePlaceholder, String trapReason) { String regex = START + "CallStaticJava" + MID + "uncommon_trap.*" + trapReason + END; beforeMatching(irNodePlaceholder, regex); } private static void parsePredicateNodes(String irNodePlaceholder, String label) { - String regex = START + "ParsePredicate" + MID + "#" + label + "[ ]*!jvms:" + END; + String regex = START + "ParsePredicate" + MID + "#" + label + " " + END; IR_NODE_MAPPINGS.put(irNodePlaceholder, new SinglePhaseRangeEntry(CompilePhase.AFTER_PARSING, regex, CompilePhase.AFTER_PARSING, - CompilePhase.PHASEIDEALLOOP_ITERATIONS)); + CompilePhase.AFTER_LOOP_OPTS)); } private static void loadOfNodes(String irNodePlaceholder, String irNodeRegex) { diff --git a/test/hotspot/jtreg/compiler/loopopts/TestUnswitchPredicateCloning.java b/test/hotspot/jtreg/compiler/loopopts/TestUnswitchPredicateCloning.java new file mode 100644 index 00000000000..01a438595de --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestUnswitchPredicateCloning.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.loopopts; + +import compiler.lib.ir_framework.*; +import java.util.Random; +import jdk.test.lib.Utils; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8346552 + * @summary Test that all parse predicates are cloned after loop unswitching. + * @key randomness + * @library /test/lib / + * @run driver compiler.loopopts.TestUnswitchPredicateCloning + */ + +public class TestUnswitchPredicateCloning { + static final int SIZE = 100; + + private static final Random random = Utils.getRandomInstance(); + + public static void main(String[] strArr) { + TestFramework.run(); + } + + @Run(test = {"testUnswitchingBeforePredication", "testPredicationBeforeUnswitching", "testUnswitchingUncounted"}) + @Warmup(0) + private static void runNoWarmup() { + final int idx = random.nextInt(SIZE); + final boolean cond = random.nextBoolean(); + int res = testUnswitchingBeforePredication(idx); + Asserts.assertEQ(SIZE * idx, res); + res = testPredicationBeforeUnswitching(idx, cond); + Asserts.assertEQ((SIZE * (SIZE - 1)) / 2 + (cond ? SIZE * idx : 0), res); + res = testUnswitchingUncounted(cond); + Asserts.assertEQ((SIZE * (SIZE - 1)) / 2 + (cond ? SIZE : 0), res); + } + + @DontInline + private static int[] getArr() { + int[] arr = new int[SIZE]; + for (int i = 0; i < SIZE; i++) { + arr[i] = i; + } + return arr; + } + + @Test + // Check that Loop Unswitching doubled the number of Parse Predicates: We have + // them at the true- and false-path-loop. Note that the Loop Limit Check Parse + // Predicate is not cloned when we already have a counted loop. + @IR(counts = { IRNode.LOOP_PARSE_PREDICATE, "3", + IRNode.PROFILED_LOOP_PARSE_PREDICATE, "3", + IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, "3", + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "3" }, + phase = CompilePhase.BEFORE_LOOP_UNSWITCHING) + // Since we know that Loop Predication happens after Loop Unswitching, we can test the + // have already been removed in the beautify loop phase. + @IR(counts = { IRNode.LOOP_PARSE_PREDICATE, "4", + IRNode.PROFILED_LOOP_PARSE_PREDICATE, "4", + IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, "3", + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "4" }, + phase = CompilePhase.BEFORE_LOOP_PREDICATION_RC) + // Check that Opaque Template Assertion Predicates are added in Loop Predication + // even if Loop Predication only happens after Loop Unswitching. + @IR(failOn = { IRNode.OPAQUE_TEMPLATE_ASSERTION_PREDICATE }, + phase = CompilePhase.AFTER_LOOP_UNSWITCHING) + @IR(counts = { IRNode.OPAQUE_TEMPLATE_ASSERTION_PREDICATE, "2" }, + phase = CompilePhase.AFTER_LOOP_PREDICATION_RC) + static int testUnswitchingBeforePredication(int j) { + int zero = 34; + int limit = 2; + + // Ensure zero == 0 is only known after CCP + for (; limit < 4; limit *= 2) { + } + for (int i = 2; i < limit; i++) { + zero = 0; + } + + int[] arr = getArr(); + int res = 0; + for (int i = 0; i < arr.length; i++) { + // Trigger unswitching only after CCP + if (zero == 0) { + // Trigger range check after loop unswitching + res += arr[j]; + } else { + res += arr[i]; + } + } + + return res; + } + + @Test + // Check that Loop Unswitching doubled the number of Parse and Template + // Assertion Predicates. Again, the Loop Limit Check Parse Predicate + // remains at the Loop Selector since this is a counted loop. + @IR(failOn = { IRNode.OPAQUE_TEMPLATE_ASSERTION_PREDICATE }, + phase = CompilePhase.BEFORE_LOOP_PREDICATION_RC) + @IR(counts = { IRNode.OPAQUE_TEMPLATE_ASSERTION_PREDICATE, "2", + IRNode.LOOP_PARSE_PREDICATE, "1", + IRNode.PROFILED_LOOP_PARSE_PREDICATE, "1", + IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, "1", + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "1" }, + phase = CompilePhase.BEFORE_LOOP_UNSWITCHING) + // After Loop Unswitching and after removing the killed predicates. + @IR(counts = { IRNode.OPAQUE_TEMPLATE_ASSERTION_PREDICATE, "4", + IRNode.LOOP_PARSE_PREDICATE, "2", + IRNode.PROFILED_LOOP_PARSE_PREDICATE, "2", + IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, "1", + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "2" }, + phase = CompilePhase.PHASEIDEALLOOP2) + static int testPredicationBeforeUnswitching(int j, boolean cond) { + int[] arr = getArr(); + int res = 0; + for (int i = 0; i < arr.length; i++) { + if (cond) { + res += arr[j]; + } + res += arr[i]; + } + return res; + } + + @Test + // Check that Loop Unswitching doubled the number of all Parse Predicates. + // Since this is not counted loop, the Loop Limit Check Parse Predicate + // has to be cloned to both unswitched loops. + @IR(counts = { IRNode.LOOP_PARSE_PREDICATE, "1", + IRNode.PROFILED_LOOP_PARSE_PREDICATE, "1", + IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, "1", + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "1" }, + phase = CompilePhase.BEFORE_LOOP_UNSWITCHING) + // After Loop Unswitching and after removing the killed predicates all + // Parse Predicates are doubled. + @IR(counts = { IRNode.LOOP_PARSE_PREDICATE, "2", + IRNode.PROFILED_LOOP_PARSE_PREDICATE, "2", + IRNode.LOOP_LIMIT_CHECK_PARSE_PREDICATE, "2", + IRNode.AUTO_VECTORIZATION_CHECK_PARSE_PREDICATE, "2" }, + failOn = { IRNode.COUNTED_LOOP }, + phase = CompilePhase.PHASEIDEALLOOP1) + @IR(failOn = { IRNode.COUNTED_LOOP }) + static int testUnswitchingUncounted(boolean cond) { + int[] arr = getArr(); + int res = 0; + int i = 0; + while (i < arr.length) { + if (cond) { + res += 1; + } + res += arr[i]; + + i = arr[i] + 1; // effectively i += 1, but don't tell the compiler! + } + + return res; + } +} \ No newline at end of file From 290d24d16adcef6b9f0f5ac789b125fd7bac66a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 24 Apr 2025 08:36:35 +0000 Subject: [PATCH 002/118] 8355400: Better git detection in update_copyright_year.sh Reviewed-by: erikj, chagedorn --- make/scripts/update_copyright_year.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/make/scripts/update_copyright_year.sh b/make/scripts/update_copyright_year.sh index bb61d48c91c..578ab4cbc99 100644 --- a/make/scripts/update_copyright_year.sh +++ b/make/scripts/update_copyright_year.sh @@ -1,7 +1,7 @@ #!/bin/bash -f # -# Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -41,10 +41,6 @@ set -e # To allow total changes counting shopt -s lastpipe -# Get an absolute path to this script, since that determines the top-level directory. -this_script_dir=`dirname $0` -this_script_dir=`cd $this_script_dir > /dev/null && pwd` - # Temp area tmp=/tmp/`basename $0`.${USER}.$$ rm -f -r ${tmp} @@ -98,10 +94,16 @@ while getopts "c:fhy:" option; do done # VCS check +git_installed=false +which git > /dev/null && git_installed=true +if [ "$git_installed" != "true" ]; then + echo "Error: This script requires git. Please install it." + exit 1 +fi git_found=false -[ -d "${this_script_dir}/../../.git" ] && git_found=true +git status &> /dev/null && git_found=true if [ "$git_found" != "true" ]; then - echo "Error: Please execute script from within make/scripts." + echo "Error: Please execute script from within a JDK git repository." exit 1 else echo "Using Git version control system" From be6e4406d8c9024bb368ed9dc22d4a6df2a0846a Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 24 Apr 2025 09:10:43 +0000 Subject: [PATCH 003/118] 8349139: C2: Div looses dependency on condition that guarantees divisor not zero in counted loop Reviewed-by: chagedorn, epeter, qamai --- src/hotspot/share/opto/loopTransform.cpp | 29 +++++++- src/hotspot/share/opto/loopnode.cpp | 18 +++++ src/hotspot/share/opto/loopnode.hpp | 10 ++- src/hotspot/share/opto/loopopts.cpp | 23 ------ src/hotspot/share/opto/predicates.cpp | 2 +- .../TestDivDependentOnMainLoopGuard.java | 73 +++++++++++++++++++ .../TestMainLoopNoBackedgeFloatingDiv.java | 58 +++++++++++++++ 7 files changed, 181 insertions(+), 32 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java create mode 100644 test/hotspot/jtreg/compiler/controldependency/TestMainLoopNoBackedgeFloatingDiv.java diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 7de53466e21..f7783e19c9c 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1299,6 +1299,22 @@ Node *PhaseIdealLoop::clone_up_backedge_goo(Node *back_ctrl, Node *preheader_ctr return n; } +// When a counted loop is created, the loop phi type may be narrowed down. As a consequence, the control input of some +// nodes may be cleared: in particular in the case of a division by the loop iv, the Div node would lose its control +// dependency if the loop phi is never zero. After pre/main/post loops are created (and possibly unrolling), the +// loop phi type is only correct if the loop is indeed reachable: there's an implicit dependency between the loop phi +// type and the zero trip guard for the main or post loop and as a consequence a dependency between the Div node and the +// zero trip guard. This makes the dependency explicit by adding a CastII for the loop entry input of the loop phi. If +// the backedge of the main or post loop is removed, a Div node won't be able to float above the zero trip guard of the +// loop and can't execute even if the loop is not reached. +void PhaseIdealLoop::cast_incr_before_loop(Node* incr, Node* ctrl, CountedLoopNode* loop) { + Node* castii = new CastIINode(ctrl, incr, TypeInt::INT, ConstraintCastNode::UnconditionalDependency); + register_new_node(castii, ctrl); + Node* phi = loop->phi(); + assert(phi->in(LoopNode::EntryControl) == incr, "replacing wrong input?"); + _igvn.replace_input_of(phi, LoopNode::EntryControl, castii); +} + #ifdef ASSERT void PhaseIdealLoop::ensure_zero_trip_guard_proj(Node* node, bool is_main_loop) { assert(node->is_IfProj(), "must be the zero trip guard If node"); @@ -1453,6 +1469,8 @@ void PhaseIdealLoop::insert_pre_post_loops(IdealLoopTree *loop, Node_List &old_n initialize_assertion_predicates_for_main_loop(pre_head, main_head, first_node_index_in_pre_loop_body, last_node_index_in_pre_loop_body, DEBUG_ONLY(last_node_index_from_backedge_goo COMMA) old_new); + // CastII for the main loop: + cast_incr_before_loop(pre_incr, min_taken, main_head); // Step B4: Shorten the pre-loop to run only 1 iteration (for now). // RCE and alignment may change this later. @@ -1593,7 +1611,7 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old // Insert post loops. Add a post loop to the given loop passed. Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, CountedLoopNode* main_head, CountedLoopEndNode* main_end, - Node*& incr, Node* limit, CountedLoopNode*& post_head) { + Node* incr, Node* limit, CountedLoopNode*& post_head) { IfNode* outer_main_end = main_end; IdealLoopTree* outer_loop = loop; if (main_head->is_strip_mined()) { @@ -1682,6 +1700,7 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, DEBUG_ONLY(ensure_zero_trip_guard_proj(post_head->in(LoopNode::EntryControl), false);) initialize_assertion_predicates_for_post_loop(main_head, post_head, first_node_index_in_cloned_loop_body); + cast_incr_before_loop(zer_opaq->in(1), zer_taken, post_head); return new_main_exit; } @@ -1777,8 +1796,8 @@ void PhaseIdealLoop::create_assertion_predicates_at_main_or_post_loop(CountedLoo // to do because these control dependent nodes on the old target loop entry created by clone_up_backedge_goo() were // pinned on the loop backedge before. The Assertion Predicates are not control dependent on these nodes in any way. void PhaseIdealLoop::rewire_old_target_loop_entry_dependency_to_new_entry( - LoopNode* target_loop_head, const Node* old_target_loop_entry, - const uint node_index_before_new_assertion_predicate_nodes) { + CountedLoopNode* target_loop_head, const Node* old_target_loop_entry, + const uint node_index_before_new_assertion_predicate_nodes) { Node* new_main_loop_entry = target_loop_head->skip_strip_mined()->in(LoopNode::EntryControl); if (new_main_loop_entry == old_target_loop_entry) { // No Assertion Predicates added. @@ -1788,6 +1807,7 @@ void PhaseIdealLoop::rewire_old_target_loop_entry_dependency_to_new_entry( for (DUIterator_Fast imax, i = old_target_loop_entry->fast_outs(imax); i < imax; i++) { Node* out = old_target_loop_entry->fast_out(i); if (!out->is_CFG() && out->_idx < node_index_before_new_assertion_predicate_nodes) { + assert(out != target_loop_head->init_trip(), "CastII on loop entry?"); _igvn.replace_input_of(out, 0, new_main_loop_entry); set_ctrl(out, new_main_loop_entry); --i; @@ -2677,7 +2697,8 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree* loop) { if (b_test._test == BoolTest::lt) { // Range checks always use lt // The underflow and overflow limits: 0 <= scale*I+offset < limit add_constraint(stride_con, lscale_con, offset, zero, limit, next_limit_ctrl, &pre_limit, &main_limit); - Node* init = cl->init_trip(); + Node* init = cl->uncasted_init_trip(true); + Node* opaque_init = new OpaqueLoopInitNode(C, init); register_new_node(opaque_init, loop_entry); diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index b0ed29d8567..c3f411eea94 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -6058,6 +6058,24 @@ CountedLoopEndNode* CountedLoopNode::find_pre_loop_end() { return pre_end; } +Node* CountedLoopNode::uncasted_init_trip(bool uncast) { + Node* init = init_trip(); + if (uncast && init->is_CastII()) { + // skip over the cast added by PhaseIdealLoop::cast_incr_before_loop() when pre/post/main loops are created because + // it can get in the way of type propagation. For instance, the index tested by an Assertion Predicate, if the cast + // is not skipped over, could be (1): + // (AddI (CastII (AddI pre_loop_iv -2) int) 1) + // while without the cast, it is (2): + // (AddI (AddI pre_loop_iv -2) 1) + // which is be transformed to (3): + // (AddI pre_loop_iv -1) + // The compiler may be able to constant fold the Assertion Predicate condition for (3) but not (1) + assert(init->as_CastII()->carry_dependency() && skip_assertion_predicates_with_halt() == init->in(0), "casted iv phi from pre loop expected"); + init = init->in(1); + } + return init; +} + //------------------------------get_late_ctrl---------------------------------- // Compute latest legal control. Node *PhaseIdealLoop::get_late_ctrl( Node *n, Node *early ) { diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index ef958ced8c3..5a1fceacf9e 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -365,6 +365,8 @@ class CountedLoopNode : public BaseCountedLoopNode { Node* is_canonical_loop_entry(); CountedLoopEndNode* find_pre_loop_end(); + Node* uncasted_init_trip(bool uncasted); + #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif @@ -973,6 +975,8 @@ class PhaseIdealLoop : public PhaseTransform { return ctrl; } + void cast_incr_before_loop(Node* incr, Node* ctrl, CountedLoopNode* loop); + #ifdef ASSERT static void ensure_zero_trip_guard_proj(Node* node, bool is_main_loop); #endif @@ -998,7 +1002,7 @@ class PhaseIdealLoop : public PhaseTransform { CountedLoopNode* target_loop_head, const NodeInLoopBody& _node_in_loop_body, bool kill_old_template); - void rewire_old_target_loop_entry_dependency_to_new_entry(LoopNode* target_loop_head, + void rewire_old_target_loop_entry_dependency_to_new_entry(CountedLoopNode* target_loop_head, const Node* old_target_loop_entry, uint node_index_before_new_assertion_predicate_nodes); void insert_loop_limit_check_predicate(ParsePredicateSuccessProj* loop_limit_check_parse_proj, Node* cmp_limit, @@ -1352,7 +1356,7 @@ class PhaseIdealLoop : public PhaseTransform { // Add post loop after the given loop. Node *insert_post_loop(IdealLoopTree* loop, Node_List& old_new, CountedLoopNode* main_head, CountedLoopEndNode* main_end, - Node*& incr, Node* limit, CountedLoopNode*& post_head); + Node* incr, Node* limit, CountedLoopNode*& post_head); // Add a vector post loop between a vector main loop and the current post loop void insert_vector_post_loop(IdealLoopTree *loop, Node_List &old_new); @@ -1580,8 +1584,6 @@ class PhaseIdealLoop : public PhaseTransform { // Attempt to use a conditional move instead of a phi/branch Node *conditional_move( Node *n ); - bool split_thru_phi_could_prevent_vectorization(Node* n, Node* n_blk); - // Check for aggressive application of 'split-if' optimization, // using basic block level info. void split_if_with_blocks ( VectorSet &visited, Node_Stack &nstack); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index e896196c6cf..b8bbaa964e8 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1089,25 +1089,6 @@ void PhaseIdealLoop::try_move_store_after_loop(Node* n) { } } -// Split some nodes that take a counted loop phi as input at a counted -// loop can cause vectorization of some expressions to fail -bool PhaseIdealLoop::split_thru_phi_could_prevent_vectorization(Node* n, Node* n_blk) { - if (!n_blk->is_CountedLoop()) { - return false; - } - - int opcode = n->Opcode(); - - if (opcode != Op_AndI && - opcode != Op_MulI && - opcode != Op_RotateRight && - opcode != Op_RShiftI) { - return false; - } - - return n->in(1) == n_blk->as_BaseCountedLoop()->phi(); -} - //------------------------------split_if_with_blocks_pre----------------------- // Do the real work in a non-recursive function. Data nodes want to be // cloned in the pre-order so they can feed each other nicely. @@ -1194,10 +1175,6 @@ Node *PhaseIdealLoop::split_if_with_blocks_pre( Node *n ) { return n; } - if (split_thru_phi_could_prevent_vectorization(n, n_blk)) { - return n; - } - // Check for having no control input; not pinned. Allow // dominating control. if (n->in(0)) { diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index 78061801e6a..d6078e50d69 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -758,7 +758,7 @@ void AssertionPredicateIfCreator::create_halt_node(IfFalseNode* fail_proj, Ideal } OpaqueLoopInitNode* TemplateAssertionPredicateCreator::create_opaque_init(Node* new_control) const { - OpaqueLoopInitNode* opaque_init = new OpaqueLoopInitNode(_phase->C, _loop_head->init_trip()); + OpaqueLoopInitNode* opaque_init = new OpaqueLoopInitNode(_phase->C, _loop_head->uncasted_init_trip(_loop_head->is_main_loop())); _phase->register_new_node(opaque_init, new_control); return opaque_init; } diff --git a/test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java b/test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java new file mode 100644 index 00000000000..a6b7a462743 --- /dev/null +++ b/test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8349139 + * @summary C2: Div looses dependency on condition that guarantees divisor not null in counted loop + * @library /test/lib / + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestDivDependentOnMainLoopGuard::* + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:StressSeed=35878193 TestDivDependentOnMainLoopGuard + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestDivDependentOnMainLoopGuard::* + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM TestDivDependentOnMainLoopGuard + * @run main/othervm -Xcomp -XX:CompileOnly=TestDivDependentOnMainLoopGuard::* TestDivDependentOnMainLoopGuard + */ + +import jdk.test.lib.Utils; +import java.util.Random; + +public class TestDivDependentOnMainLoopGuard { + + public static final int N = 400; + private static final Random RANDOM = Utils.getRandomInstance(); + public static final int stop = RANDOM.nextInt(0, 68); + + public int iArrFld[]=new int[N]; + + public void mainTest(String[] strArr1, int otherPhi) { + + int i=57657, i1=577, i2=6, i3=157, i4=12, i23=61271; + boolean bArr[]=new boolean[N]; + + for (i = 9; 379 > i; i++) { + i2 = 1; + do { + i1 <<= i3; + } while (++i2 < 68); + for (i23 = 68; i23 > stop; otherPhi=i23-1, i23--) { + bArr[i23 + 1] = true; + try { + i1 = (-42360 / i23); + iArrFld[i + 1] = otherPhi; + } catch (ArithmeticException a_e) {} + } + } + } + + public static void main(String[] strArr) { + TestDivDependentOnMainLoopGuard _instance = new TestDivDependentOnMainLoopGuard(); + for (int i = 0; i < 10; i++ ) { + _instance.mainTest(strArr, 0); + } + } +} diff --git a/test/hotspot/jtreg/compiler/controldependency/TestMainLoopNoBackedgeFloatingDiv.java b/test/hotspot/jtreg/compiler/controldependency/TestMainLoopNoBackedgeFloatingDiv.java new file mode 100644 index 00000000000..29da59da6d3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/controldependency/TestMainLoopNoBackedgeFloatingDiv.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8349139 + * @summary C2: Div looses dependency on condition that guarantees divisor not null in counted loop + * @run main/othervm -XX:-BackgroundCompilation TestMainLoopNoBackedgeFloatingDiv + */ + +public class TestMainLoopNoBackedgeFloatingDiv { + private static int field; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test1(1000, 0, false); + test1Helper(1000, 0, false, false); + } + test1(1, 0, false); + } + + private static int test1(int stop, int res, boolean alwaysTrueInMain) { + stop = Integer.max(stop, 1); + res = test1Helper(stop, res, alwaysTrueInMain, true); + return res; + } + + private static int test1Helper(int stop, int res, boolean alwaysTrueInMain, boolean flag) { + for (int i = stop; i >= 1; i--) { + res = res / i; + if (alwaysTrueInMain) { + break; + } + alwaysTrueInMain = flag; + } + return res; + } +} From 74a2c831a2af55c66317ca8aead53fde2a2a6900 Mon Sep 17 00:00:00 2001 From: Saranya Natarajan Date: Thu, 24 Apr 2025 09:33:15 +0000 Subject: [PATCH 004/118] 8352620: C2: rename MemNode::memory_type() to MemNode::value_basic_type() Reviewed-by: rcastanedalo, thartmann --- src/hotspot/share/opto/escape.cpp | 4 +-- src/hotspot/share/opto/memnode.cpp | 8 ++--- src/hotspot/share/opto/memnode.hpp | 50 +++++++++++++++------------ src/hotspot/share/opto/superword.cpp | 12 +++---- src/hotspot/share/opto/vectornode.hpp | 4 +-- 5 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index decc43a212a..1fb34e799b2 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -2826,14 +2826,14 @@ int ConnectionGraph::find_init_values_null(JavaObjectNode* pta, PhaseValues* pha offsets_worklist.append(offset); Node* value = nullptr; if (ini != nullptr) { - // StoreP::memory_type() == T_ADDRESS + // StoreP::value_basic_type() == T_ADDRESS BasicType ft = UseCompressedOops ? T_NARROWOOP : T_ADDRESS; Node* store = ini->find_captured_store(offset, type2aelembytes(ft, true), phase); // Make sure initializing store has the same type as this AddP. // This AddP may reference non existing field because it is on a // dead branch of bimorphic call which is not eliminated yet. if (store != nullptr && store->is_Store() && - store->as_Store()->memory_type() == ft) { + store->as_Store()->value_basic_type() == ft) { value = store->in(MemNode::ValueIn); #ifdef ASSERT if (VerifyConnectionGraph) { diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 9cd3dcfee41..24b81b894cb 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1213,12 +1213,12 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseValues* phase) const { // (This is one of the few places where a generic PhaseTransform // can create new nodes. Think of it as lazily manifesting // virtually pre-existing constants.) - if (memory_type() != T_VOID) { + if (value_basic_type() != T_VOID) { if (ReduceBulkZeroing || find_array_copy_clone(ld_alloc, in(MemNode::Memory)) == nullptr) { // If ReduceBulkZeroing is disabled, we need to check if the allocation does not belong to an // ArrayCopyNode clone. If it does, then we cannot assume zero since the initialization is done // by the ArrayCopyNode. - return phase->zerocon(memory_type()); + return phase->zerocon(value_basic_type()); } } else { // TODO: materialize all-zero vector constant @@ -2047,7 +2047,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { int stable_dimension = (ary->stable_dimension() > 0 ? ary->stable_dimension() - 1 : 0); const Type* con_type = Type::make_constant_from_array_element(aobj->as_array(), off, stable_dimension, - memory_type(), is_unsigned()); + value_basic_type(), is_unsigned()); if (con_type != nullptr) { return con_type; } @@ -2115,7 +2115,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { const TypeInstPtr* tinst = tp->is_instptr(); ciObject* const_oop = tinst->const_oop(); if (!is_mismatched_access() && off != Type::OffsetBot && const_oop != nullptr && const_oop->is_instance()) { - const Type* con_type = Type::make_constant_from_field(const_oop->as_instance(), off, is_unsigned(), memory_type()); + const Type* con_type = Type::make_constant_from_field(const_oop->as_instance(), off, is_unsigned(), value_basic_type()); if (con_type != nullptr) { return con_type; } diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index f17db05e683..157cc1866a0 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -134,12 +134,16 @@ class MemNode : public Node { virtual int store_Opcode() const { return -1; } // What is the type of the value in memory? (T_VOID mean "unspecified".) - virtual BasicType memory_type() const = 0; + // The returned type is a property of the value that is loaded/stored and + // not the memory that is accessed. For mismatched memory accesses + // they might differ. For instance, a value of type 'short' may be stored + // into an array of elements of type 'long'. + virtual BasicType value_basic_type() const = 0; virtual int memory_size() const { #ifdef ASSERT - return type2aelembytes(memory_type(), true); + return type2aelembytes(value_basic_type(), true); #else - return type2aelembytes(memory_type()); + return type2aelembytes(value_basic_type()); #endif } @@ -337,7 +341,7 @@ class LoadBNode : public LoadNode { virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type* Value(PhaseGVN* phase) const; virtual int store_Opcode() const { return Op_StoreB; } - virtual BasicType memory_type() const { return T_BYTE; } + virtual BasicType value_basic_type() const { return T_BYTE; } }; //------------------------------LoadUBNode------------------------------------- @@ -351,7 +355,7 @@ class LoadUBNode : public LoadNode { virtual Node* Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type* Value(PhaseGVN* phase) const; virtual int store_Opcode() const { return Op_StoreB; } - virtual BasicType memory_type() const { return T_BYTE; } + virtual BasicType value_basic_type() const { return T_BYTE; } }; //------------------------------LoadUSNode------------------------------------- @@ -365,7 +369,7 @@ class LoadUSNode : public LoadNode { virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type* Value(PhaseGVN* phase) const; virtual int store_Opcode() const { return Op_StoreC; } - virtual BasicType memory_type() const { return T_CHAR; } + virtual BasicType value_basic_type() const { return T_CHAR; } }; //------------------------------LoadSNode-------------------------------------- @@ -379,7 +383,7 @@ class LoadSNode : public LoadNode { virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type* Value(PhaseGVN* phase) const; virtual int store_Opcode() const { return Op_StoreC; } - virtual BasicType memory_type() const { return T_SHORT; } + virtual BasicType value_basic_type() const { return T_SHORT; } }; //------------------------------LoadINode-------------------------------------- @@ -391,7 +395,7 @@ class LoadINode : public LoadNode { virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual int store_Opcode() const { return Op_StoreI; } - virtual BasicType memory_type() const { return T_INT; } + virtual BasicType value_basic_type() const { return T_INT; } }; //------------------------------LoadRangeNode---------------------------------- @@ -424,7 +428,7 @@ class LoadLNode : public LoadNode { virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegL; } virtual int store_Opcode() const { return Op_StoreL; } - virtual BasicType memory_type() const { return T_LONG; } + virtual BasicType value_basic_type() const { return T_LONG; } bool require_atomic_access() const { return _require_atomic_access; } #ifndef PRODUCT @@ -453,7 +457,7 @@ class LoadFNode : public LoadNode { virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegF; } virtual int store_Opcode() const { return Op_StoreF; } - virtual BasicType memory_type() const { return T_FLOAT; } + virtual BasicType value_basic_type() const { return T_FLOAT; } }; //------------------------------LoadDNode-------------------------------------- @@ -474,7 +478,7 @@ class LoadDNode : public LoadNode { virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegD; } virtual int store_Opcode() const { return Op_StoreD; } - virtual BasicType memory_type() const { return T_DOUBLE; } + virtual BasicType value_basic_type() const { return T_DOUBLE; } bool require_atomic_access() const { return _require_atomic_access; } #ifndef PRODUCT @@ -503,7 +507,7 @@ class LoadPNode : public LoadNode { virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegP; } virtual int store_Opcode() const { return Op_StoreP; } - virtual BasicType memory_type() const { return T_ADDRESS; } + virtual BasicType value_basic_type() const { return T_ADDRESS; } }; @@ -516,7 +520,7 @@ class LoadNNode : public LoadNode { virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegN; } virtual int store_Opcode() const { return Op_StoreN; } - virtual BasicType memory_type() const { return T_NARROWOOP; } + virtual BasicType value_basic_type() const { return T_NARROWOOP; } }; //------------------------------LoadKlassNode---------------------------------- @@ -555,7 +559,7 @@ class LoadNKlassNode : public LoadNNode { virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegN; } virtual int store_Opcode() const { return Op_StoreNKlass; } - virtual BasicType memory_type() const { return T_NARROWKLASS; } + virtual BasicType value_basic_type() const { return T_NARROWKLASS; } virtual const Type* Value(PhaseGVN* phase) const; virtual Node* Identity(PhaseGVN* phase); @@ -666,7 +670,7 @@ class StoreBNode : public StoreNode { : StoreNode(c, mem, adr, at, val, mo) {} virtual int Opcode() const; virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual BasicType memory_type() const { return T_BYTE; } + virtual BasicType value_basic_type() const { return T_BYTE; } }; //------------------------------StoreCNode------------------------------------- @@ -677,7 +681,7 @@ class StoreCNode : public StoreNode { : StoreNode(c, mem, adr, at, val, mo) {} virtual int Opcode() const; virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual BasicType memory_type() const { return T_CHAR; } + virtual BasicType value_basic_type() const { return T_CHAR; } }; //------------------------------StoreINode------------------------------------- @@ -687,7 +691,7 @@ class StoreINode : public StoreNode { StoreINode(Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, MemOrd mo) : StoreNode(c, mem, adr, at, val, mo) {} virtual int Opcode() const; - virtual BasicType memory_type() const { return T_INT; } + virtual BasicType value_basic_type() const { return T_INT; } }; //------------------------------StoreLNode------------------------------------- @@ -705,7 +709,7 @@ class StoreLNode : public StoreNode { StoreLNode(Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, MemOrd mo, bool require_atomic_access = false) : StoreNode(c, mem, adr, at, val, mo), _require_atomic_access(require_atomic_access) {} virtual int Opcode() const; - virtual BasicType memory_type() const { return T_LONG; } + virtual BasicType value_basic_type() const { return T_LONG; } bool require_atomic_access() const { return _require_atomic_access; } #ifndef PRODUCT @@ -723,7 +727,7 @@ class StoreFNode : public StoreNode { StoreFNode(Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, MemOrd mo) : StoreNode(c, mem, adr, at, val, mo) {} virtual int Opcode() const; - virtual BasicType memory_type() const { return T_FLOAT; } + virtual BasicType value_basic_type() const { return T_FLOAT; } }; //------------------------------StoreDNode------------------------------------- @@ -741,7 +745,7 @@ class StoreDNode : public StoreNode { MemOrd mo, bool require_atomic_access = false) : StoreNode(c, mem, adr, at, val, mo), _require_atomic_access(require_atomic_access) {} virtual int Opcode() const; - virtual BasicType memory_type() const { return T_DOUBLE; } + virtual BasicType value_basic_type() const { return T_DOUBLE; } bool require_atomic_access() const { return _require_atomic_access; } #ifndef PRODUCT @@ -760,7 +764,7 @@ class StorePNode : public StoreNode { StorePNode(Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, MemOrd mo) : StoreNode(c, mem, adr, at, val, mo) {} virtual int Opcode() const; - virtual BasicType memory_type() const { return T_ADDRESS; } + virtual BasicType value_basic_type() const { return T_ADDRESS; } }; //------------------------------StoreNNode------------------------------------- @@ -770,7 +774,7 @@ class StoreNNode : public StoreNode { StoreNNode(Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, MemOrd mo) : StoreNode(c, mem, adr, at, val, mo) {} virtual int Opcode() const; - virtual BasicType memory_type() const { return T_NARROWOOP; } + virtual BasicType value_basic_type() const { return T_NARROWOOP; } }; //------------------------------StoreNKlassNode-------------------------------------- @@ -780,7 +784,7 @@ class StoreNKlassNode : public StoreNNode { StoreNKlassNode(Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, MemOrd mo) : StoreNNode(c, mem, adr, at, val, mo) {} virtual int Opcode() const; - virtual BasicType memory_type() const { return T_NARROWKLASS; } + virtual BasicType value_basic_type() const { return T_NARROWKLASS; } }; //------------------------------SCMemProjNode--------------------------------------- diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 0746715f065..5e34249aee8 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -158,7 +158,7 @@ void SuperWord::unrolling_analysis(const VLoop &vloop, int &local_loop_unroll_fa // Ignore nodes with non-primitive type. BasicType bt; if (n->is_Mem()) { - bt = n->as_Mem()->memory_type(); + bt = n->as_Mem()->value_basic_type(); } else { bt = n->bottom_type()->basic_type(); } @@ -191,7 +191,7 @@ void SuperWord::unrolling_analysis(const VLoop &vloop, int &local_loop_unroll_fa BasicType bt; Node* n = lpt->_body.at(i); if (n->is_Mem()) { - bt = n->as_Mem()->memory_type(); + bt = n->as_Mem()->value_basic_type(); } else { bt = n->bottom_type()->basic_type(); } @@ -564,7 +564,7 @@ void SuperWord::collect_valid_memops(GrowableArray& memops) const { const VPointer& p = vpointer(mem); if (p.is_valid() && !mem->is_LoadStore() && - is_java_primitive(mem->memory_type())) { + is_java_primitive(mem->value_basic_type())) { memops.append(MemOp(mem, &p, original_index++)); } }); @@ -764,8 +764,8 @@ bool SuperWord::are_adjacent_refs(Node* s1, Node* s2) const { if (!in_bb(s1) || !in_bb(s2)) return false; // Do not use superword for non-primitives - if (!is_java_primitive(s1->as_Mem()->memory_type()) || - !is_java_primitive(s2->as_Mem()->memory_type())) { + if (!is_java_primitive(s1->as_Mem()->value_basic_type()) || + !is_java_primitive(s2->as_Mem()->value_basic_type())) { return false; } @@ -2593,7 +2593,7 @@ void VLoopTypes::compute_vector_element_type() { const Type* VLoopTypes::container_type(Node* n) const { int opc = n->Opcode(); if (n->is_Mem()) { - BasicType bt = n->as_Mem()->memory_type(); + BasicType bt = n->as_Mem()->value_basic_type(); if (n->is_Store() && (bt == T_CHAR)) { // Use T_SHORT type instead of T_CHAR for stored values because any // preceding arithmetic operation extends values to signed Int. diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index 36706a7b7a1..ae817598d39 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -1084,7 +1084,7 @@ class LoadVectorNode : public LoadNode { virtual int Opcode() const; virtual uint ideal_reg() const { return Matcher::vector_ideal_reg(memory_size()); } - virtual BasicType memory_type() const { return T_VOID; } + virtual BasicType value_basic_type() const { return T_VOID; } virtual int memory_size() const { return vect_type()->length_in_bytes(); } virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); @@ -1157,7 +1157,7 @@ class StoreVectorNode : public StoreNode { virtual int Opcode() const; virtual uint ideal_reg() const { return Matcher::vector_ideal_reg(memory_size()); } - virtual BasicType memory_type() const { return T_VOID; } + virtual BasicType value_basic_type() const { return T_VOID; } virtual int memory_size() const { return vect_type()->length_in_bytes(); } virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); From 6254046f508049a4e568f0f2eae51dc10da392c1 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 24 Apr 2025 10:27:50 +0000 Subject: [PATCH 005/118] 8320909: C2: Adapt IGVN's enqueuing logic to match idealization of AndNode with LShift operand Reviewed-by: epeter, thartmann --- src/hotspot/share/opto/phaseX.cpp | 28 +++++++ .../compiler/c2/gvn/MissedOptCastII.java | 68 +++++++++++++++++ .../c2/gvn/MissedOptWithShiftConvAnd.java | 72 ++++++++++++++++++ .../c2/gvn/MissedOptWithShiftConvCastAnd.java | 76 +++++++++++++++++++ 4 files changed, 244 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/c2/gvn/MissedOptCastII.java create mode 100644 test/hotspot/jtreg/compiler/c2/gvn/MissedOptWithShiftConvAnd.java create mode 100644 test/hotspot/jtreg/compiler/c2/gvn/MissedOptWithShiftConvCastAnd.java diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index f0c8f9d7649..9be15b153b3 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1728,6 +1728,34 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ } } } + + /* AndNode has a special handling when one of the operands is a LShiftNode: + * (LHS << s) & RHS + * if RHS fits in less than s bits, the value of this expression is 0. + * The difficulty is that there might be a conversion node (ConvI2L) between + * the LShiftINode and the AndLNode, like so: + * AndLNode(ConvI2L(LShiftI(LHS, s)), RHS) + * This case is handled by And[IL]Node::Value(PhaseGVN*) + * (see `AndIL_min_trailing_zeros`). + * + * But, when the shift is updated during IGVN, pushing the user (ConvI2L) + * is not enough: there might be no update happening there. We need to + * directly push the And[IL]Node on the worklist, jumping over ConvI2L. + * + * Moreover we can have ConstraintCasts in between. It may look like + * ConstraintCast+ -> ConvI2L -> ConstraintCast+ -> And + * and And[IL]Node::Value(PhaseGVN*) still handles that by looking through casts. + * So we must deal with that as well. + */ + if (use->is_ConstraintCast() || use_op == Op_ConvI2L) { + auto is_boundary = [](Node* n){ return !n->is_ConstraintCast() && n->Opcode() != Op_ConvI2L; }; + auto push_and_to_worklist = [&worklist](Node* n){ + if (n->Opcode() == Op_AndL || n->Opcode() == Op_AndI) { + worklist.push(n); + } + }; + use->visit_uses(push_and_to_worklist, is_boundary); + } } /** diff --git a/test/hotspot/jtreg/compiler/c2/gvn/MissedOptCastII.java b/test/hotspot/jtreg/compiler/c2/gvn/MissedOptCastII.java new file mode 100644 index 00000000000..a32fa020065 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/gvn/MissedOptCastII.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8319372 8320909 + * @summary Missed optimization in IGVN because `CastIINode::Value` used to + * look for deep structures. Reported in 8320909. Fixed in 8319372. + * + * @run main/othervm + * -XX:CompileCommand=quiet + * -XX:CompileCommand=compileonly,MissedOptCastII::* + * -XX:-TieredCompilation -Xcomp + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:+StressIGVN -XX:VerifyIterativeGVN=10 + * MissedOptCastII + */ + +/* + * @test + * @bug 8319372 8320909 + * + * @run main/othervm MissedOptCastII + */ + +public class MissedOptCastII { + static long res = 0; + + static void test() { + int i, i1 = 0, k, l = -4; + for (i = 0; i < 100; i++) { + for (int j = 0; j < 10; j++) { + for (k = 1; k < 2; k++) { + i1 = l; + l += k * k; + if (l != 0) { + res = i + i1 + Float.floatToIntBits(2); + } + } + } + } + res = i + i1; + } + + public static void main(String[] args) { + test(); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/gvn/MissedOptWithShiftConvAnd.java b/test/hotspot/jtreg/compiler/c2/gvn/MissedOptWithShiftConvAnd.java new file mode 100644 index 00000000000..1b81b81aca5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/gvn/MissedOptWithShiftConvAnd.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8320909 + * @summary AndNode has a special handling when one of the operands is a LShiftNode: + * (LHS << s) & RHS + * if RHS fits in less than s bits, the value of this expression is 0. + * The case where there is a conversion node between the Shift and the And as in: + * AndLNode(ConvI2L(LShiftI(LHS, s)), RHS) + * is also handled, but the AndL must be pushed directly in IGVN's worklist because + * ConvI2L might not have an update when its input change. In this example, the + * input was a Phi with a dead branch and becomes a LShiftI with the same type. + * + * @run main/othervm + * -XX:CompileOnly=MissedOptWithShiftConvAnd::test + * -XX:-TieredCompilation -Xbatch + * -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=10 + * MissedOptWithShiftConvAnd + */ + +/* + * @test + * @bug 8320909 + * + * @run main/othervm MissedOptWithShiftConvAnd + */ + +public class MissedOptWithShiftConvAnd { + static long lFld; + + public static void main(String[] strArr) { + for (int i = 0; i < 100; i++) { + test(); + } + } + + static void test() { + long l3 = 0; + int i13 = 1; + for (l3 = 8; l3 < 200; ++l3) { + for (int i12 = 1; i12 < 2; i12++) { + i13 <<= 73; + } + } + for (int i14 = 1; 2 > i14; ++i14) { + i13 &= l3; + lFld = i13; + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/gvn/MissedOptWithShiftConvCastAnd.java b/test/hotspot/jtreg/compiler/c2/gvn/MissedOptWithShiftConvCastAnd.java new file mode 100644 index 00000000000..f354464fa50 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/gvn/MissedOptWithShiftConvCastAnd.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8320909 + * @summary Similar to MissedOptWithShiftConvAnd, but with CastII on the way. + * @library /test/lib + * + * @run main/othervm + * -XX:CompileOnly=MissedOptWithShiftConvCastAnd::test + * -XX:-TieredCompilation -Xbatch + * -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=10 + * MissedOptWithShiftConvCastAnd + */ + +/* + * @test + * @bug 8320909 + * @library /test/lib + * + * @run main/othervm MissedOptWithShiftConvCastAnd + */ + +import jdk.test.lib.Utils; + +public class MissedOptWithShiftConvCastAnd { + static long instanceCount; + + public static void main(String[] args) throws Exception { + Thread thread = new Thread() { + public void run() { + test(0); + } + }; + // Give thread some time to trigger compilation + thread.setDaemon(true); + thread.start(); + Thread.sleep(Utils.adjustTimeout(500)); + } + + static void test(int x) { + for (int i = 3; ; ++i) { + for (int j = 5; j > 1; --j) { + instanceCount >>= x <<= 16; + } + x >>>= 16; + for (int j = 1; j < 5; j++) { + try { + x = 1; + } catch (ArithmeticException a_e) { + } + } + } + } +} From d3f31b0d8e9c90f3dc8e97a299c9e0b7f5b05284 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 24 Apr 2025 11:43:53 +0000 Subject: [PATCH 006/118] 8347719: [REDO] Portable implementation of FORBID_C_FUNCTION and ALLOW_C_FUNCTION Reviewed-by: tschatzl, jsjolen --- src/hotspot/os/aix/libodm_aix.cpp | 3 +- src/hotspot/os/aix/loadlib_aix.cpp | 17 ++-- src/hotspot/os/aix/os_aix.cpp | 9 +- src/hotspot/os/aix/porting_aix.cpp | 5 +- src/hotspot/os/bsd/decoder_machO.cpp | 8 +- src/hotspot/os/linux/decoder_linux.cpp | 9 +- .../os/linux/gc/z/zMountPoint_linux.cpp | 9 +- src/hotspot/os/linux/mallocInfoDcmd.cpp | 9 +- .../os/posix/forbiddenFunctions_posix.hpp | 64 +++++++++++++ src/hotspot/os/posix/os_posix.cpp | 11 +-- .../posix/permitForbiddenFunctions_posix.hpp | 45 ++++++++++ .../os/windows/forbiddenFunctions_windows.hpp | 38 ++++++++ src/hotspot/os/windows/os_windows.cpp | 9 +- .../permitForbiddenFunctions_windows.hpp | 45 ++++++++++ src/hotspot/os/windows/symbolengine.cpp | 5 +- src/hotspot/share/jvmci/jvmciEnv.cpp | 3 +- src/hotspot/share/logging/logTagSet.cpp | 5 +- src/hotspot/share/nmt/mallocSiteTable.cpp | 6 +- src/hotspot/share/nmt/memMapPrinter.cpp | 9 +- src/hotspot/share/nmt/nmtPreInit.cpp | 7 +- src/hotspot/share/runtime/os.cpp | 12 +-- .../share/utilities/compilerWarnings.hpp | 64 ++++++++++--- .../share/utilities/compilerWarnings_gcc.hpp | 89 +++++++++++++------ .../utilities/compilerWarnings_visCPP.hpp | 44 +++------ .../share/utilities/forbiddenFunctions.hpp | 79 ++++++++++++++++ .../share/utilities/globalDefinitions.hpp | 30 +------ .../utilities/permitForbiddenFunctions.hpp | 73 +++++++++++++++ test/hotspot/gtest/code/test_codestrings.cpp | 3 + .../shenandoah/test_shenandoahNumberSeq.cpp | 2 + .../test_shenandoahSimpleBitMap.cpp | 6 +- test/hotspot/gtest/gtestMain.cpp | 5 +- test/hotspot/gtest/unittest.hpp | 4 + 32 files changed, 564 insertions(+), 163 deletions(-) create mode 100644 src/hotspot/os/posix/forbiddenFunctions_posix.hpp create mode 100644 src/hotspot/os/posix/permitForbiddenFunctions_posix.hpp create mode 100644 src/hotspot/os/windows/forbiddenFunctions_windows.hpp create mode 100644 src/hotspot/os/windows/permitForbiddenFunctions_windows.hpp create mode 100644 src/hotspot/share/utilities/forbiddenFunctions.hpp create mode 100644 src/hotspot/share/utilities/permitForbiddenFunctions.hpp diff --git a/src/hotspot/os/aix/libodm_aix.cpp b/src/hotspot/os/aix/libodm_aix.cpp index 9fe0fb7abd8..854fd5e2b79 100644 --- a/src/hotspot/os/aix/libodm_aix.cpp +++ b/src/hotspot/os/aix/libodm_aix.cpp @@ -30,6 +30,7 @@ #include #include "runtime/arguments.hpp" #include "runtime/os.hpp" +#include "utilities/permitForbiddenFunctions.hpp" dynamicOdm::dynamicOdm() { @@ -59,7 +60,7 @@ dynamicOdm::~dynamicOdm() { } -void odmWrapper::clean_data() { if (_data) { free(_data); _data = nullptr; } } +void odmWrapper::clean_data() { if (_data) { permit_forbidden_function::free(_data); _data = nullptr; } } int odmWrapper::class_offset(const char *field, bool is_aix_5) diff --git a/src/hotspot/os/aix/loadlib_aix.cpp b/src/hotspot/os/aix/loadlib_aix.cpp index 90a7271ad6d..e7dbd775e37 100644 --- a/src/hotspot/os/aix/loadlib_aix.cpp +++ b/src/hotspot/os/aix/loadlib_aix.cpp @@ -38,6 +38,7 @@ #include "logging/log.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" // For loadquery() #include @@ -58,7 +59,7 @@ class StringList { // Enlarge list. If oom, leave old list intact and return false. bool enlarge() { int cap2 = _cap + 64; - char** l2 = (char**) ::realloc(_list, sizeof(char*) * cap2); + char** l2 = (char**) permit_forbidden_function::realloc(_list, sizeof(char*) * cap2); if (!l2) { return false; } @@ -76,7 +77,7 @@ class StringList { } } assert0(_cap > _num); - char* s2 = ::strdup(s); + char* s2 = permit_forbidden_function::strdup(s); if (!s2) { return nullptr; } @@ -170,7 +171,7 @@ static void free_entry_list(loaded_module_t** start) { loaded_module_t* lm = *start; while (lm) { loaded_module_t* const lm2 = lm->next; - ::free(lm); + permit_forbidden_function::free(lm); lm = lm2; } *start = nullptr; @@ -193,7 +194,7 @@ static bool reload_table() { uint8_t* buffer = nullptr; size_t buflen = 1024; for (;;) { - buffer = (uint8_t*) ::realloc(buffer, buflen); + buffer = (uint8_t*) permit_forbidden_function::realloc(buffer, buflen); if (loadquery(L_GETINFO, buffer, buflen) == -1) { if (errno == ENOMEM) { buflen *= 2; @@ -229,7 +230,7 @@ static bool reload_table() { for (;;) { - loaded_module_t* lm = (loaded_module_t*) ::malloc(sizeof(loaded_module_t)); + loaded_module_t* lm = (loaded_module_t*) permit_forbidden_function::malloc(sizeof(loaded_module_t)); if (!lm) { log_warning(os)("OOM."); goto cleanup; @@ -250,7 +251,7 @@ static bool reload_table() { if (!lm->path) { log_warning(os)("OOM."); - free(lm); + permit_forbidden_function::free(lm); goto cleanup; } @@ -272,7 +273,7 @@ static bool reload_table() { lm->member = g_stringlist.add(p_mbr_name); if (!lm->member) { log_warning(os)("OOM."); - free(lm); + permit_forbidden_function::free(lm); goto cleanup; } } else { @@ -320,7 +321,7 @@ static bool reload_table() { free_entry_list(&new_list); } - ::free(buffer); + permit_forbidden_function::free(buffer); return rc; diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index d913139ffdf..49dcebd0083 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -73,6 +73,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "utilities/vmError.hpp" #if INCLUDE_JFR #include "jfr/support/jfrNativeLibraryLoadEvent.hpp" @@ -369,9 +370,9 @@ static void query_multipage_support() { // or by environment variable LDR_CNTRL (suboption DATAPSIZE). If none is given, // default should be 4K. { - void* p = ::malloc(16*M); + void* p = permit_forbidden_function::malloc(16*M); g_multipage_support.datapsize = os::Aix::query_pagesize(p); - ::free(p); + permit_forbidden_function::free(p); } // Query default shm page size (LDR_CNTRL SHMPSIZE). @@ -1398,7 +1399,7 @@ static struct { } vmem; static void vmembk_add(char* addr, size_t size, size_t pagesize, int type) { - vmembk_t* p = (vmembk_t*) ::malloc(sizeof(vmembk_t)); + vmembk_t* p = (vmembk_t*) permit_forbidden_function::malloc(sizeof(vmembk_t)); assert0(p); if (p) { MiscUtils::AutoCritSect lck(&vmem.cs); @@ -1427,7 +1428,7 @@ static void vmembk_remove(vmembk_t* p0) { for (vmembk_t** pp = &(vmem.first); *pp; pp = &((*pp)->next)) { if (*pp == p0) { *pp = p0->next; - ::free(p0); + permit_forbidden_function::free(p0); return; } } diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp index cbc45d3e122..2235d3da686 100644 --- a/src/hotspot/os/aix/porting_aix.cpp +++ b/src/hotspot/os/aix/porting_aix.cpp @@ -39,6 +39,7 @@ #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include #include #include @@ -250,7 +251,7 @@ bool AixSymbols::get_function_name ( p_name[namelen-1] = '\0'; } if (demangled_name != nullptr) { - ALLOW_C_FUNCTION(::free, ::free(demangled_name)); + permit_forbidden_function::free(demangled_name); } } } else { @@ -1081,7 +1082,7 @@ void* Aix_dlopen(const char* filename, int Flags, int *eno, const char** error_r if (g_handletable_used == max_handletable) { // No place in array anymore; increase array. unsigned new_max = MAX2(max_handletable * 2, init_num_handles); - struct handletableentry* new_tab = (struct handletableentry*)::realloc(p_handletable, new_max * sizeof(struct handletableentry)); + struct handletableentry* new_tab = (struct handletableentry*) permit_forbidden_function::realloc(p_handletable, new_max * sizeof(struct handletableentry)); assert(new_tab != nullptr, "no more memory for handletable"); if (new_tab == nullptr) { *error_report = "dlopen: no more memory for handletable"; diff --git a/src/hotspot/os/bsd/decoder_machO.cpp b/src/hotspot/os/bsd/decoder_machO.cpp index 173e030a7b5..15592d172fe 100644 --- a/src/hotspot/os/bsd/decoder_machO.cpp +++ b/src/hotspot/os/bsd/decoder_machO.cpp @@ -27,6 +27,8 @@ #include "decoder_machO.hpp" #include "jvm.h" #include "memory/allocation.inline.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include #include @@ -42,9 +44,9 @@ bool MachODecoder::demangle(const char* symbol, char *buf, int buflen) { // may use different malloc/realloc mechanism that allocates 'buf'. if ((result = abi::__cxa_demangle(symbol, nullptr, nullptr, &status)) != nullptr) { jio_snprintf(buf, buflen, "%s", result); - // call c library's free - ::free(result); - return true; + // call c library's free + permit_forbidden_function::free(result); + return true; } return false; } diff --git a/src/hotspot/os/linux/decoder_linux.cpp b/src/hotspot/os/linux/decoder_linux.cpp index 26b435f69e1..bfe5c537864 100644 --- a/src/hotspot/os/linux/decoder_linux.cpp +++ b/src/hotspot/os/linux/decoder_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "utilities/decoder_elf.hpp" #include "utilities/elfFile.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include @@ -46,9 +47,9 @@ bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) { // may use different malloc/realloc mechanism that allocates 'buf'. if ((result = abi::__cxa_demangle(symbol, nullptr, nullptr, &status)) != nullptr) { jio_snprintf(buf, buflen, "%s", result); - // call c library's free - ALLOW_C_FUNCTION(::free, ::free(result);) - return true; + // call c library's free + permit_forbidden_function::free(result); + return true; } return false; } diff --git a/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp b/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp index 60ce39179ff..92c5cb713ac 100644 --- a/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp @@ -28,6 +28,7 @@ #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include #include @@ -62,11 +63,11 @@ char* ZMountPoint::get_mountpoint(const char* line, const char* filesystem) cons strcmp(line_filesystem, filesystem) != 0 || access(line_mountpoint, R_OK|W_OK|X_OK) != 0) { // Not a matching or accessible filesystem - ALLOW_C_FUNCTION(::free, ::free(line_mountpoint);) + permit_forbidden_function::free(line_mountpoint); line_mountpoint = nullptr; } - ALLOW_C_FUNCTION(::free, ::free(line_filesystem);) + permit_forbidden_function::free(line_filesystem); return line_mountpoint; } @@ -90,14 +91,14 @@ void ZMountPoint::get_mountpoints(const char* filesystem, ZArray* mountpo } // readline will return malloced memory. Need raw ::free, not os::free. - ALLOW_C_FUNCTION(::free, ::free(line);) + permit_forbidden_function::free(line); fclose(fd); } void ZMountPoint::free_mountpoints(ZArray* mountpoints) const { ZArrayIterator iter(mountpoints); for (char* mountpoint; iter.next(&mountpoint);) { - ALLOW_C_FUNCTION(::free, ::free(mountpoint);) // *not* os::free + permit_forbidden_function::free(mountpoint); // *not* os::free } mountpoints->clear(); } diff --git a/src/hotspot/os/linux/mallocInfoDcmd.cpp b/src/hotspot/os/linux/mallocInfoDcmd.cpp index ad98d5edece..1a2368b1e50 100644 --- a/src/hotspot/os/linux/mallocInfoDcmd.cpp +++ b/src/hotspot/os/linux/mallocInfoDcmd.cpp @@ -26,6 +26,7 @@ #include "os_linux.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include @@ -35,7 +36,7 @@ void MallocInfoDcmd::execute(DCmdSource source, TRAPS) { #ifdef __GLIBC__ char* buf; size_t size; - ALLOW_C_FUNCTION(::open_memstream, FILE* stream = ::open_memstream(&buf, &size);) + FILE* stream = ::open_memstream(&buf, &size); if (stream == nullptr) { _output->print_cr("Error: Could not call malloc_info(3)"); return; @@ -43,7 +44,7 @@ void MallocInfoDcmd::execute(DCmdSource source, TRAPS) { int err = os::Linux::malloc_info(stream); if (err == 0) { - ALLOW_C_FUNCTION(::fflush, fflush(stream);) + fflush(stream); _output->print_raw(buf); _output->cr(); } else if (err == -1) { @@ -53,8 +54,8 @@ void MallocInfoDcmd::execute(DCmdSource source, TRAPS) { } else { ShouldNotReachHere(); } - ALLOW_C_FUNCTION(::fclose, ::fclose(stream);) - ALLOW_C_FUNCTION(::free, ::free(buf);) + ::fclose(stream); + permit_forbidden_function::free(buf); #else _output->print_cr(malloc_info_unavailable); #endif // __GLIBC__ diff --git a/src/hotspot/os/posix/forbiddenFunctions_posix.hpp b/src/hotspot/os/posix/forbiddenFunctions_posix.hpp new file mode 100644 index 00000000000..9f9881202c7 --- /dev/null +++ b/src/hotspot/os/posix/forbiddenFunctions_posix.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_POSIX_FORBIDDENFUNCTIONS_POSIX_HPP +#define OS_POSIX_FORBIDDENFUNCTIONS_POSIX_HPP + +#include "utilities/compilerWarnings.hpp" + +// For types used in the signatures. +#include + +// Workaround for noreturn functions: _exit - see the clang +// definition of FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE. +#ifdef __clang__ +#include +#endif + +// If needed, add os::strndup and use that instead. +FORBID_C_FUNCTION(char* strndup(const char*, size_t), "don't use"); + +// These are unimplementable for Windows, and they aren't useful for a +// POSIX implementation of NMT either. +// https://stackoverflow.com/questions/62962839/stdaligned-alloc-missing-from-visual-studio-2019 +FORBID_C_FUNCTION(int posix_memalign(void**, size_t, size_t), "don't use"); +FORBID_C_FUNCTION(void* aligned_alloc(size_t, size_t), "don't use"); + +// realpath with a null second argument mallocs a string for the result. +// With a non-null second argument, there is a risk of buffer overrun. +PRAGMA_DIAG_PUSH +FORBIDDEN_FUNCTION_IGNORE_CLANG_FORTIFY_WARNING +FORBID_C_FUNCTION(char* realpath(const char*, char*), "use os::realpath"); +PRAGMA_DIAG_POP + +// Returns a malloc'ed string. +FORBID_C_FUNCTION(char* get_current_dir_name(), "use os::get_current_directory"); + +// Problematic API that should never be used. +FORBID_C_FUNCTION(char* getwd(char*), "use os::get_current_directory"); + +// BSD utility that is subtly different from realloc. +FORBID_C_FUNCTION(void* reallocf(void*, size_t), "use os::realloc"); + +#endif // OS_POSIX_FORBIDDENFUNCTIONS_POSIX_HPP diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index a36d6b87641..df084ae6898 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -49,6 +49,7 @@ #include "utilities/formatBuffer.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "utilities/vmError.hpp" #if INCLUDE_JFR #include "jfr/support/jfrNativeLibraryLoadEvent.hpp" @@ -930,11 +931,11 @@ ssize_t os::connect(int fd, struct sockaddr* him, socklen_t len) { } void os::exit(int num) { - ALLOW_C_FUNCTION(::exit, ::exit(num);) + permit_forbidden_function::exit(num); } void os::_exit(int num) { - ALLOW_C_FUNCTION(::_exit, ::_exit(num);) + permit_forbidden_function::_exit(num); } void os::naked_yield() { @@ -991,7 +992,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { // This assumes platform realpath() is implemented according to POSIX.1-2008. // POSIX.1-2008 allows to specify null for the output buffer, in which case // output buffer is dynamically allocated and must be ::free()'d by the caller. - ALLOW_C_FUNCTION(::realpath, char* p = ::realpath(filename, nullptr);) + char* p = permit_forbidden_function::realpath(filename, nullptr); if (p != nullptr) { if (strlen(p) < outbuflen) { strcpy(outbuf, p); @@ -999,7 +1000,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } else { errno = ENAMETOOLONG; } - ALLOW_C_FUNCTION(::free, ::free(p);) // *not* os::free + permit_forbidden_function::free(p); // *not* os::free } else { // Fallback for platforms struggling with modern Posix standards (AIX 5.3, 6.1). If realpath // returns EINVAL, this may indicate that realpath is not POSIX.1-2008 compatible and @@ -1008,7 +1009,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { // a memory overwrite. if (errno == EINVAL) { outbuf[outbuflen - 1] = '\0'; - ALLOW_C_FUNCTION(::realpath, p = ::realpath(filename, outbuf);) + p = permit_forbidden_function::realpath(filename, outbuf); if (p != nullptr) { guarantee(outbuf[outbuflen - 1] == '\0', "realpath buffer overwrite detected."); result = p; diff --git a/src/hotspot/os/posix/permitForbiddenFunctions_posix.hpp b/src/hotspot/os/posix/permitForbiddenFunctions_posix.hpp new file mode 100644 index 00000000000..3ff8c383a31 --- /dev/null +++ b/src/hotspot/os/posix/permitForbiddenFunctions_posix.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_POSIX_PERMITFORBIDDENFUNCTIONS_POSIX_HPP +#define OS_POSIX_PERMITFORBIDDENFUNCTIONS_POSIX_HPP + +#include "utilities/compilerWarnings.hpp" +#include "utilities/globalDefinitions.hpp" + +// Provide wrappers for some functions otherwise forbidden from use in HotSpot. +// See forbiddenFunctions.hpp for details. + +namespace permit_forbidden_function { +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS + +// Used by the POSIX implementation of os::realpath. +inline char* realpath(const char* path, char* resolved_path) { + return ::realpath(path, resolved_path); +} + +END_ALLOW_FORBIDDEN_FUNCTIONS +} // namespace permit_forbidden_function + +#endif // OS_POSIX_PERMITFORBIDDENFUNCTIONS_POSIX_HPP diff --git a/src/hotspot/os/windows/forbiddenFunctions_windows.hpp b/src/hotspot/os/windows/forbiddenFunctions_windows.hpp new file mode 100644 index 00000000000..81599522ed4 --- /dev/null +++ b/src/hotspot/os/windows/forbiddenFunctions_windows.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_WINDOWS_FORBIDDENFUNCTIONS_WINDOWS_HPP +#define OS_WINDOWS_FORBIDDENFUNCTIONS_WINDOWS_HPP + +#include "utilities/compilerWarnings.hpp" + +#include // for size_t + +// _fullpath with a null first argument mallocs a string for the result. +FORBID_IMPORTED_C_FUNCTION(char* _fullpath(char*, const char*, size_t), "use os::realpath"); + +// _snprintf does NOT null terminate if the output would exceed the buffer size. +FORBID_C_FUNCTION(int _snprintf(char*, size_t, const char*, ...), "use os::snprintf"); + +#endif // OS_WINDOWS_FORBIDDENFUNCTIONS_WINDOWS_HPP diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 84e89334feb..959a0616834 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -76,6 +76,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/macros.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "utilities/population_count.hpp" #include "utilities/vmError.hpp" #include "windbghelp.hpp" @@ -4358,9 +4359,9 @@ static void exit_process_or_thread(Ept what, int exit_code) { if (what == EPT_THREAD) { _endthreadex((unsigned)exit_code); } else if (what == EPT_PROCESS) { - ALLOW_C_FUNCTION(::exit, ::exit(exit_code);) + permit_forbidden_function::exit(exit_code); } else { // EPT_PROCESS_DIE - ALLOW_C_FUNCTION(::_exit, ::_exit(exit_code);) + permit_forbidden_function::_exit(exit_code); } // Should not reach here @@ -5131,7 +5132,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } char* result = nullptr; - ALLOW_C_FUNCTION(::_fullpath, char* p = ::_fullpath(nullptr, filename, 0);) + char* p = permit_forbidden_function::_fullpath(nullptr, filename, 0); if (p != nullptr) { if (strlen(p) < outbuflen) { strcpy(outbuf, p); @@ -5139,7 +5140,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } else { errno = ENAMETOOLONG; } - ALLOW_C_FUNCTION(::free, ::free(p);) // *not* os::free + permit_forbidden_function::free(p); // *not* os::free } return result; } diff --git a/src/hotspot/os/windows/permitForbiddenFunctions_windows.hpp b/src/hotspot/os/windows/permitForbiddenFunctions_windows.hpp new file mode 100644 index 00000000000..99e77464fbd --- /dev/null +++ b/src/hotspot/os/windows/permitForbiddenFunctions_windows.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_WINDOWS_PERMITFORBIDDENFUNCTIONS_WINDOWS_HPP +#define OS_WINDOWS_PERMITFORBIDDENFUNCTIONS_WINDOWS_HPP + +#include "utilities/compilerWarnings.hpp" +#include "utilities/globalDefinitions.hpp" + +// Provide wrappers for some functions otherwise forbidden from use in HotSpot. +// See forbiddenFunctions.hpp for details. + +namespace permit_forbidden_function { +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS + +// Used by the Windows implementation of os::realpath. +inline char* _fullpath(char* absPath, const char* relPath, size_t maxLength) { + return ::_fullpath(absPath, relPath, maxLength); +} + +END_ALLOW_FORBIDDEN_FUNCTIONS +} // namespace permit_forbidden_function + +#endif // OS_WINDOWS_PERMITFORBIDDENFUNCTIONS_WINDOWS_HPP diff --git a/src/hotspot/os/windows/symbolengine.cpp b/src/hotspot/os/windows/symbolengine.cpp index 83cb930f7bf..8f6f6cf09c6 100644 --- a/src/hotspot/os/windows/symbolengine.cpp +++ b/src/hotspot/os/windows/symbolengine.cpp @@ -26,6 +26,7 @@ #include "symbolengine.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "windbghelp.hpp" #include @@ -102,7 +103,7 @@ class SimpleBufferWithFallback { virtual void initialize () { assert(_p == nullptr && _capacity == 0, "Only call once."); const size_t bytes = OPTIMAL_CAPACITY * sizeof(T); - T* q = (T*) ::malloc(bytes); + T* q = (T*) permit_forbidden_function::malloc(bytes); if (q != nullptr) { _p = q; _capacity = OPTIMAL_CAPACITY; @@ -118,7 +119,7 @@ class SimpleBufferWithFallback { // case, where two buffers need to be of identical capacity. void reset_to_fallback_capacity() { if (_p != _fallback_buffer) { - ::free(_p); + permit_forbidden_function::free(_p); } _p = _fallback_buffer; _capacity = (int)(sizeof(_fallback_buffer) / sizeof(T)); diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index a23b09c3c1e..5a0efef0bd3 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -46,6 +46,7 @@ #include "runtime/javaCalls.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/os.hpp" +#include "utilities/permitForbiddenFunctions.hpp" JVMCICompileState::JVMCICompileState(CompileTask* task, JVMCICompiler* compiler): _task(task), @@ -612,7 +613,7 @@ JVMCIEnv::~JVMCIEnv() { if (_init_error_msg != nullptr) { // The memory allocated in libjvmci was not allocated with os::malloc // so must not be freed with os::free. - ALLOW_C_FUNCTION(::free, ::free((void*) _init_error_msg);) + permit_forbidden_function::free((void*)_init_error_msg); } if (_init_error != JNI_OK) { return; diff --git a/src/hotspot/share/logging/logTagSet.cpp b/src/hotspot/share/logging/logTagSet.cpp index f7b0e01331c..4719d0a926e 100644 --- a/src/hotspot/share/logging/logTagSet.cpp +++ b/src/hotspot/share/logging/logTagSet.cpp @@ -34,6 +34,7 @@ #include "memory/allocation.inline.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" LogTagSet* LogTagSet::_list = nullptr; size_t LogTagSet::_ntagsets = 0; @@ -149,7 +150,7 @@ void LogTagSet::vwrite(LogLevelType level, const char* fmt, va_list args) { } else { // Buffer too small, allocate a large enough buffer using malloc/free to avoid circularity. // Since logging is a very basic function, conceivably used within NMT itself, avoid os::malloc/free - ALLOW_C_FUNCTION(::malloc, char* newbuf = (char*)::malloc(newbuf_len * sizeof(char));) + char* newbuf = (char*)permit_forbidden_function::malloc(newbuf_len * sizeof(char)); if (newbuf != nullptr) { prefix_len = _write_prefix(newbuf, newbuf_len); ret = os::vsnprintf(newbuf + prefix_len, newbuf_len - prefix_len, fmt, saved_args); @@ -159,7 +160,7 @@ void LogTagSet::vwrite(LogLevelType level, const char* fmt, va_list args) { if (ret < 0) { log(level, "Log message newbuf issue"); } - ALLOW_C_FUNCTION(::free, ::free(newbuf);) + permit_forbidden_function::free(newbuf); } else { // Native OOM, use buf to output the least message. At this moment buf is full of either // truncated prefix or truncated prefix + string. Put trunc_msg at the end of buf. diff --git a/src/hotspot/share/nmt/mallocSiteTable.cpp b/src/hotspot/share/nmt/mallocSiteTable.cpp index 71e75551e2f..55fa5f0b173 100644 --- a/src/hotspot/share/nmt/mallocSiteTable.cpp +++ b/src/hotspot/share/nmt/mallocSiteTable.cpp @@ -25,6 +25,8 @@ #include "memory/allocation.inline.hpp" #include "nmt/mallocSiteTable.hpp" #include "runtime/atomic.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" // Malloc site hashtable buckets MallocSiteHashtableEntry** MallocSiteTable::_table = nullptr; @@ -40,9 +42,7 @@ const MallocSiteHashtableEntry* MallocSiteTable::_hash_entry_allocation_site = n * time, it is in single-threaded mode from JVM perspective. */ bool MallocSiteTable::initialize() { - - ALLOW_C_FUNCTION(::calloc, - _table = (MallocSiteHashtableEntry**)::calloc(table_size, sizeof(MallocSiteHashtableEntry*));) + _table = (MallocSiteHashtableEntry**)permit_forbidden_function::calloc(table_size, sizeof(MallocSiteHashtableEntry*)); if (_table == nullptr) { return false; } diff --git a/src/hotspot/share/nmt/memMapPrinter.cpp b/src/hotspot/share/nmt/memMapPrinter.cpp index db67321fb1d..804a03f45e5 100644 --- a/src/hotspot/share/nmt/memMapPrinter.cpp +++ b/src/hotspot/share/nmt/memMapPrinter.cpp @@ -42,6 +42,7 @@ #include "runtime/vmThread.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" // Note: throughout this code we will use the term "VMA" for OS system level memory mapping @@ -95,8 +96,8 @@ class CachedNMTInformation : public VirtualMemoryWalker { _count(0), _capacity(0), _last(0) {} ~CachedNMTInformation() { - ALLOW_C_FUNCTION(free, ::free(_ranges);) - ALLOW_C_FUNCTION(free, ::free(_mem_tags);) + permit_forbidden_function::free(_ranges); + permit_forbidden_function::free(_mem_tags); } bool add(const void* from, const void* to, MemTag mem_tag) { @@ -111,8 +112,8 @@ class CachedNMTInformation : public VirtualMemoryWalker { // Enlarge if needed const size_t new_capacity = MAX2((size_t)4096, 2 * _capacity); // Unfortunately, we need to allocate manually, raw, since we must prevent NMT deadlocks (ThreadCritical). - ALLOW_C_FUNCTION(realloc, _ranges = (Range*)::realloc(_ranges, new_capacity * sizeof(Range));) - ALLOW_C_FUNCTION(realloc, _mem_tags = (MemTag*)::realloc(_mem_tags, new_capacity * sizeof(MemTag));) + _ranges = (Range*)permit_forbidden_function::realloc(_ranges, new_capacity * sizeof(Range)); + _mem_tags = (MemTag*)permit_forbidden_function::realloc(_mem_tags, new_capacity * sizeof(MemTag)); if (_ranges == nullptr || _mem_tags == nullptr) { // In case of OOM lets make no fuss. Just return. return false; diff --git a/src/hotspot/share/nmt/nmtPreInit.cpp b/src/hotspot/share/nmt/nmtPreInit.cpp index 34a2d8dd7d2..3b9150366dc 100644 --- a/src/hotspot/share/nmt/nmtPreInit.cpp +++ b/src/hotspot/share/nmt/nmtPreInit.cpp @@ -29,12 +29,13 @@ #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" // Obviously we cannot use os::malloc for any dynamic allocation during pre-NMT-init, so we must use // raw malloc; to make this very clear, wrap them. -static void* raw_malloc(size_t s) { ALLOW_C_FUNCTION(::malloc, return ::malloc(s);) } -static void* raw_realloc(void* old, size_t s) { ALLOW_C_FUNCTION(::realloc, return ::realloc(old, s);) } -static void raw_free(void* p) { ALLOW_C_FUNCTION(::free, ::free(p);) } +static void* raw_malloc(size_t s) { return permit_forbidden_function::malloc(s); } +static void* raw_realloc(void* old, size_t s) { return permit_forbidden_function::realloc(old, s); } +static void raw_free(void* p) { permit_forbidden_function::free(p); } // To keep matters simple we just raise a fatal error on OOM. Since preinit allocation // is just used for pre-VM-initialization mallocs, none of which are optional, we don't diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 943f81d752c..67b25be8eb9 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -76,7 +76,9 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/fastrand.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "utilities/powerOfTwo.hpp" #ifdef LINUX @@ -117,7 +119,7 @@ int os::snprintf_checked(char* buf, size_t len, const char* fmt, ...) { } int os::vsnprintf(char* buf, size_t len, const char* fmt, va_list args) { - ALLOW_C_FUNCTION(::vsnprintf, int result = ::vsnprintf(buf, len, fmt, args);) + int result = permit_forbidden_function::vsnprintf(buf, len, fmt, args); // If an encoding error occurred (result < 0) then it's not clear // whether the buffer is NUL terminated, so ensure it is. if ((result < 0) && (len > 0)) { @@ -654,7 +656,7 @@ void* os::malloc(size_t size, MemTag mem_tag, const NativeCallStack& stack) { return nullptr; } - ALLOW_C_FUNCTION(::malloc, void* const outer_ptr = ::malloc(outer_size);) + void* const outer_ptr = permit_forbidden_function::malloc(outer_size); if (outer_ptr == nullptr) { return nullptr; } @@ -721,7 +723,7 @@ void* os::realloc(void *memblock, size_t size, MemTag mem_tag, const NativeCallS header->mark_block_as_dead(); // the real realloc - ALLOW_C_FUNCTION(::realloc, void* const new_outer_ptr = ::realloc(header, new_outer_size);) + void* const new_outer_ptr = permit_forbidden_function::realloc(header, new_outer_size); if (new_outer_ptr == nullptr) { // realloc(3) failed and the block still exists. @@ -749,7 +751,7 @@ void* os::realloc(void *memblock, size_t size, MemTag mem_tag, const NativeCallS } else { // NMT disabled. - ALLOW_C_FUNCTION(::realloc, rc = ::realloc(memblock, size);) + rc = permit_forbidden_function::realloc(memblock, size); if (rc == nullptr) { return nullptr; } @@ -777,7 +779,7 @@ void os::free(void *memblock) { // When NMT is enabled this checks for heap overwrites, then deaccounts the old block. void* const old_outer_ptr = MemTracker::record_free(memblock); - ALLOW_C_FUNCTION(::free, ::free(old_outer_ptr);) + permit_forbidden_function::free(old_outer_ptr); } void os::init_random(unsigned int initval) { diff --git a/src/hotspot/share/utilities/compilerWarnings.hpp b/src/hotspot/share/utilities/compilerWarnings.hpp index ddcaf022fa6..e2c9fc289f6 100644 --- a/src/hotspot/share/utilities/compilerWarnings.hpp +++ b/src/hotspot/share/utilities/compilerWarnings.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,23 +88,61 @@ // Support warnings for use of certain C functions, except where explicitly // permitted. + +// FORBID_C_FUNCTION(Signature, Alternative) +// - Signature: the function that should not normally be used. +// - Alternative: a string literal that may be used in a warning about a use, +// often suggesting an alternative. +// Declares the C-linkage function designated by Signature to be deprecated, +// using the `deprecated` attribute with Alternative as an argument. // -// FORBID_C_FUNCTION(signature, alternative) -// - signature: the function that should not normally be used. -// - alternative: a string that may be used in a warning about a use, typically -// suggesting an alternative. +// The variants with IMPORTED in the name are to deal with Windows +// requirements, using FORBIDDEN_FUNCTION_IMPORT_SPEC. See the Visual +// Studio definition of that macro for more details. The default has +// an empty expansion. The potentially added spec must precede the +// base signature but follow all attributes. // -// ALLOW_C_FUNCTION(name, ... using statement ...) -// - name: the name of a forbidden function whose use is permitted in statement. -// - statement: a use of the otherwise forbidden function. Using a variadic -// tail allows the statement to contain non-nested commas. +// FORBID_NORETURN_C_FUNCTION deals with a clang issue. See the clang +// definition of FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE for more +// details. The default expands to `[[noreturn]]`. +#define FORBID_C_FUNCTION(Signature, Alternative) \ + extern "C" { [[deprecated(Alternative)]] Signature; } + +#ifndef FORBIDDEN_FUNCTION_IMPORT_SPEC +#define FORBIDDEN_FUNCTION_IMPORT_SPEC +#endif -#ifndef FORBID_C_FUNCTION -#define FORBID_C_FUNCTION(signature, alternative) +#ifndef FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE +#define FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE [[noreturn]] #endif -#ifndef ALLOW_C_FUNCTION -#define ALLOW_C_FUNCTION(name, ...) __VA_ARGS__ +#ifndef FORBIDDEN_FUNCTION_IGNORE_CLANG_FORTIFY_WARNING +#define FORBIDDEN_FUNCTION_IGNORE_CLANG_FORTIFY_WARNING #endif +#define FORBID_IMPORTED_C_FUNCTION(Signature, Alternative) \ + FORBID_C_FUNCTION(FORBIDDEN_FUNCTION_IMPORT_SPEC Signature, Alternative) + +#define FORBID_NORETURN_C_FUNCTION(Signature, Alternative) \ + FORBID_C_FUNCTION(FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE Signature, Alternative) + +#define FORBID_IMPORTED_NORETURN_C_FUNCTION(Signature, Alternative) \ + FORBID_NORETURN_C_FUNCTION(FORBIDDEN_FUNCTION_IMPORT_SPEC Signature, Alternative) + +// A BEGIN/END_ALLOW_FORBIDDEN_FUNCTIONS pair establishes a scope in which the +// deprecation warnings used to forbid the use of certain functions are +// suppressed. These macros are not intended for warning suppression at +// individual call sites; see permitForbiddenFunctions.hpp for the approach +// taken for that where needed. Rather, these are used to suppress warnings +// from 3rd-party code included by HotSpot, such as the gtest framework and +// C++ Standard Library headers, which may refer to functions that are +// disallowed in other parts of HotSpot. They are also used in the +// implementation of the "permit" mechanism. +#define BEGIN_ALLOW_FORBIDDEN_FUNCTIONS \ + PRAGMA_DIAG_PUSH \ + PRAGMA_DEPRECATED_IGNORED + +#define END_ALLOW_FORBIDDEN_FUNCTIONS \ + PRAGMA_DIAG_POP + #endif // SHARE_UTILITIES_COMPILERWARNINGS_HPP diff --git a/src/hotspot/share/utilities/compilerWarnings_gcc.hpp b/src/hotspot/share/utilities/compilerWarnings_gcc.hpp index 1dd5892e4c3..863cc512cca 100644 --- a/src/hotspot/share/utilities/compilerWarnings_gcc.hpp +++ b/src/hotspot/share/utilities/compilerWarnings_gcc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,32 +70,71 @@ #define PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED \ PRAGMA_DISABLE_GCC_WARNING("-Wzero-as-null-pointer-constant") -#if (__GNUC__ >= 10) -// TODO: Re-enable warning attribute for Clang once -// https://github.com/llvm/llvm-project/issues/56519 is fixed and released. -// || (defined(__clang_major__) && (__clang_major__ >= 14)) +#define PRAGMA_DEPRECATED_IGNORED \ + PRAGMA_DISABLE_GCC_WARNING("-Wdeprecated-declarations") -// Use "warning" attribute to detect uses of "forbidden" functions. +// This macro is used by the NORETURN variants of FORBID_C_FUNCTION. // -// Note: The warning attribute is available since GCC 9, but disabling pragmas -// does not work reliably in ALLOW_C_FUNCTION. GCC 10+ and up work fine. +// The [[noreturn]] attribute requires that the first declaration of a +// function has it if any have it. // -// Note: _FORTIFY_SOURCE transforms calls to certain functions into calls to -// associated "checking" functions, and that transformation seems to occur -// *before* the attribute check. We use fortification in fastdebug builds, -// so uses of functions that are both forbidden and fortified won't cause -// forbidden warnings in such builds. -#define FORBID_C_FUNCTION(signature, alternative) \ - extern "C" __attribute__((__warning__(alternative))) signature; - -// Disable warning attribute over the scope of the affected statement. -// The name serves only to document the intended function. -#define ALLOW_C_FUNCTION(name, ...) \ - PRAGMA_DIAG_PUSH \ - PRAGMA_DISABLE_GCC_WARNING("-Wattribute-warning") \ - __VA_ARGS__ \ - PRAGMA_DIAG_POP - -#endif // gcc10+ +// gcc, clang, and MSVC all provide compiler-specific alternatives to that +// attribute: __attribute__((noreturn)) for gcc and clang, +// __declspec(noreturn) for MSVC and clang. gcc and MSVC treat their +// respective compiler-specific alternatives as satisfying that requirement. +// clang does not. +// +// So clang warns if we use [[noreturn]] in the forbidding declaration and the +// library header has already been included and uses the compiler-specific +// attribute. Similarly, clang warns if we use the compiler-specific attribute +// while the library uses [[noreturn]] and the library header is included +// after the forbidding declaration. +// +// For now, we're only going to worry about the standard library, and not +// noreturn functions in some other library that we might want to forbid in +// the future. If there's more than one library to be accounted for, then +// things may get more complicated. +// +// There are several ways we could deal with this. +// +// Probably the most robust is to use the same style of noreturn attribute as +// is used by the library providing the function. That way it doesn't matter +// in which order the inclusion of the library header and the forbidding are +// performed. We could use configure to determine which to use and provide a +// macro to select on here. +// +// Another approach is to always use __attribute__ noreturn in the forbidding +// declaration, but ensure the relevant library header has been included +// before the forbidding declaration. Since there are currently only a couple +// of affected functions, this is easier to implement. So this is the +// approach being taken for now. +// +// clang's failure to treat the compiler-specific form as counting toward the +// [[noreturn]] requirement is arguably a clang bug. +// https://github.com/llvm/llvm-project/issues/131700 + +#ifdef __clang__ +#define FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE __attribute__((__noreturn__)) +#endif + +// This macro is used to suppress a warning for some uses of FORBID_C_FUNCTION. +// +// libstdc++ provides inline definitions of some functions to support +// _FORTIFY_SOURCE. clang warns about our forbidding declaration adding the +// [[deprecated]] attribute following such a definition: +// "warning: attribute declaration must precede definition [-Wignored-attributes]" +// Use this macro to suppress the warning, not getting protection when using +// that combination. Other build combinations should provide sufficient +// coverage. +// +// clang's warning in this case is arguably a clang bug. +// https://github.com/llvm/llvm-project/issues/135481 +// This issue has been fixed, with the fix probably appearing in clang 21. +#if defined(__clang__) && defined(_FORTIFY_SOURCE) +#if _FORTIFY_SOURCE > 0 +#define FORBIDDEN_FUNCTION_IGNORE_CLANG_FORTIFY_WARNING \ + PRAGMA_DISABLE_GCC_WARNING("-Wignored-attributes") +#endif +#endif #endif // SHARE_UTILITIES_COMPILERWARNINGS_GCC_HPP diff --git a/src/hotspot/share/utilities/compilerWarnings_visCPP.hpp b/src/hotspot/share/utilities/compilerWarnings_visCPP.hpp index de76b522c7b..6321388c48a 100644 --- a/src/hotspot/share/utilities/compilerWarnings_visCPP.hpp +++ b/src/hotspot/share/utilities/compilerWarnings_visCPP.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,39 +30,17 @@ #define PRAGMA_DIAG_PUSH _Pragma("warning(push)") #define PRAGMA_DIAG_POP _Pragma("warning(pop)") -// The Visual Studio implementation of FORBID_C_FUNCTION explicitly does -// nothing, because there doesn't seem to be a way to implement it for Visual -// Studio. What seems the most likely approach is to use deprecation warnings, -// but that runs into problems. -// -// (1) Declaring the function deprecated (using either __declspec(deprecated) -// or the C++14 [[deprecated]] attribute) fails with warnings like this: -// warning C4273: 'exit': inconsistent dll linkage -// It seems attributes are not simply additive with this compiler. -// -// (2) Additionally adding __declspec(dllimport) to deal with (1) fails with -// warnings like this: -// error C2375: 'vsnprintf': redefinition; different linkage -// It seems some functions in the set of interest have different linkage than -// others ("exit" is marked imported while "vsnprintf" is not, for example). -// That makes it difficult to provide a generic macro. -// -// (3) Using __pragma(deprecated(name)) fails with -// warning C4995: 'frobnicate': name was marked as #pragma deprecated -// for a *declaration* (not a use) of a 'frobnicate' function. -// -// ALLOW_C_FUNCTIONS disables deprecation warnings over the statement scope. -// Some of the functions we're interested in allowing are conditionally -// deprecated on Windows, under the control of various preprocessor defines -// such as _CRT_SECURE_NO_WARNINGS. Annotating vetted uses allows those -// warnings to catch unchecked uses. +#define PRAGMA_DEPRECATED_IGNORED PRAGMA_DISABLE_MSVC_WARNING(4996) -#define FORBID_C_FUNCTION(signature, alternative) +// This macro is used by the IMPORTED variants of FORBID_C_FUNCTION. +// +// Some, but not all, functions we want to forbid using must include a +// `__declspec(dllimport)` in the declaration. Failure to do so where needed +// leads to "redefinition; different linkage" errors for the forbidding +// declaration. But including a dllimport specifier if not present in the +// compiler's header leads to the same errors. It seems one must just know +// which are imported and which are not, and use the specifier accordingly. -#define ALLOW_C_FUNCTION(name, ...) \ - PRAGMA_DIAG_PUSH \ - PRAGMA_DISABLE_MSVC_WARNING(4996) \ - __VA_ARGS__ \ - PRAGMA_DIAG_POP +#define FORBIDDEN_FUNCTION_IMPORT_SPEC __declspec(dllimport) #endif // SHARE_UTILITIES_COMPILERWARNINGS_VISCPP_HPP diff --git a/src/hotspot/share/utilities/forbiddenFunctions.hpp b/src/hotspot/share/utilities/forbiddenFunctions.hpp new file mode 100644 index 00000000000..0bc34adf213 --- /dev/null +++ b/src/hotspot/share/utilities/forbiddenFunctions.hpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_UTILITIES_FORBIDDENFUNCTIONS_HPP +#define SHARE_UTILITIES_FORBIDDENFUNCTIONS_HPP + +#include "utilities/compilerWarnings.hpp" +#include "utilities/macros.hpp" + +// For types used in the signatures. +#include +#include + +// Workaround for noreturn functions: exit, _exit, _Exit - see the clang +// definition of FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE. +#ifdef __clang__ +#include +#endif + +#ifdef _WINDOWS +#include "forbiddenFunctions_windows.hpp" +#else +#include "forbiddenFunctions_posix.hpp" +#endif + +// Forbid the use of various C library functions. Some of these have os:: +// replacements that should be used instead. Others are considered obsolete +// or have security concerns, either with preferred alternatives, or to be +// avoided entirely. + +FORBID_IMPORTED_NORETURN_C_FUNCTION(void exit(int), "use os::exit") +FORBID_IMPORTED_NORETURN_C_FUNCTION(void _Exit(int), "use os::exit") + +// Windows puts _exit in , POSIX in . +FORBID_IMPORTED_NORETURN_C_FUNCTION(void _exit(int), "use os::exit") + +FORBID_IMPORTED_C_FUNCTION(char* strerror(int), "use os::strerror"); +FORBID_IMPORTED_C_FUNCTION(char* strtok(char*, const char*), "use strtok_r"); + +FORBID_C_FUNCTION(int sprintf(char*, const char*, ...), "use os::snprintf"); + +PRAGMA_DIAG_PUSH +FORBIDDEN_FUNCTION_IGNORE_CLANG_FORTIFY_WARNING +FORBID_C_FUNCTION(int vsprintf(char*, const char*, va_list), "use os::vsnprintf"); +FORBID_C_FUNCTION(int vsnprintf(char*, size_t, const char*, va_list), "use os::vsnprintf"); +PRAGMA_DIAG_POP + +// All of the following functions return raw C-heap pointers (sometimes as an +// option, e.g. realpath or getwd) or, in case of free(), take raw C-heap +// pointers. We generally want allocation to be done through NMT. +FORBID_IMPORTED_C_FUNCTION(void* malloc(size_t size), "use os::malloc"); +FORBID_IMPORTED_C_FUNCTION(void free(void *ptr), "use os::free"); +FORBID_IMPORTED_C_FUNCTION(void* calloc(size_t nmemb, size_t size), "use os::malloc and zero out manually"); +FORBID_IMPORTED_C_FUNCTION(void* realloc(void *ptr, size_t size), "use os::realloc"); +FORBID_IMPORTED_C_FUNCTION(char* strdup(const char *s), "use os::strdup"); +FORBID_IMPORTED_C_FUNCTION(wchar_t* wcsdup(const wchar_t *s), "don't use"); + +#endif // SHARE_UTILITIES_FORBIDDENFUNCTIONS_HPP diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 95971f16ed9..085939b0131 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -27,6 +27,7 @@ #include "utilities/compilerWarnings.hpp" #include "utilities/debug.hpp" +#include "utilities/forbiddenFunctions.hpp" #include "utilities/macros.hpp" // Get constants like JVM_T_CHAR and JVM_SIGNATURE_INT, before pulling in . @@ -173,35 +174,6 @@ inline uintptr_t p2u(const volatile void* p) { #define BOOL_TO_STR(_b_) ((_b_) ? "true" : "false") -//---------------------------------------------------------------------------------------------------- -// Forbid the use of various C library functions. -// Some of these have os:: replacements that should normally be used instead. -// Others are considered security concerns, with preferred alternatives. - -FORBID_C_FUNCTION(void exit(int), "use os::exit"); -FORBID_C_FUNCTION(void _exit(int), "use os::exit"); -FORBID_C_FUNCTION(char* strerror(int), "use os::strerror"); -FORBID_C_FUNCTION(char* strtok(char*, const char*), "use strtok_r"); -FORBID_C_FUNCTION(int sprintf(char*, const char*, ...), "use os::snprintf"); -FORBID_C_FUNCTION(int vsprintf(char*, const char*, va_list), "use os::vsnprintf"); -FORBID_C_FUNCTION(int vsnprintf(char*, size_t, const char*, va_list), "use os::vsnprintf"); - -// All of the following functions return raw C-heap pointers (sometimes as an option, e.g. realpath or getwd) -// or, in case of free(), take raw C-heap pointers. Don't use them unless you are really sure you must. -FORBID_C_FUNCTION(void* malloc(size_t size), "use os::malloc"); -FORBID_C_FUNCTION(void* calloc(size_t nmemb, size_t size), "use os::malloc and zero out manually"); -FORBID_C_FUNCTION(void free(void *ptr), "use os::free"); -FORBID_C_FUNCTION(void* realloc(void *ptr, size_t size), "use os::realloc"); -FORBID_C_FUNCTION(char* strdup(const char *s), "use os::strdup"); -FORBID_C_FUNCTION(char* strndup(const char *s, size_t n), "don't use"); -FORBID_C_FUNCTION(int posix_memalign(void **memptr, size_t alignment, size_t size), "don't use"); -FORBID_C_FUNCTION(void* aligned_alloc(size_t alignment, size_t size), "don't use"); -FORBID_C_FUNCTION(char* realpath(const char* path, char* resolved_path), "use os::realpath"); -FORBID_C_FUNCTION(char* get_current_dir_name(void), "use os::get_current_directory()"); -FORBID_C_FUNCTION(char* getwd(char *buf), "use os::get_current_directory()"); -FORBID_C_FUNCTION(wchar_t* wcsdup(const wchar_t *s), "don't use"); -FORBID_C_FUNCTION(void* reallocf(void *ptr, size_t size), "don't use"); - //---------------------------------------------------------------------------------------------------- // Constants diff --git a/src/hotspot/share/utilities/permitForbiddenFunctions.hpp b/src/hotspot/share/utilities/permitForbiddenFunctions.hpp new file mode 100644 index 00000000000..1ba42f8e386 --- /dev/null +++ b/src/hotspot/share/utilities/permitForbiddenFunctions.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_UTILITIES_PERMITFORBIDDENFUNCTIONS_HPP +#define SHARE_UTILITIES_PERMITFORBIDDENFUNCTIONS_HPP + +#include "utilities/compilerWarnings.hpp" +#include "utilities/globalDefinitions.hpp" + +#ifdef _WINDOWS +#include "permitForbiddenFunctions_windows.hpp" +#else +#include "permitForbiddenFunctions_posix.hpp" +#endif + +// Provide wrappers for some functions otherwise forbidden from use in HotSpot. +// +// There may be special circumstances where an otherwise forbidden function +// really does need to be used. One example is in the implementation of a +// corresponding os:: function. +// +// Wrapper functions are provided for such forbidden functions. These +// wrappers are defined in a context where the forbidding warnings are +// suppressed. They are defined in a special namespace, to highlight uses as +// unusual and requiring increased scrutiny. +// +// Note that there are several seemingly plausible shorter alternatives to +// these written-out wrapper functions. All that have been tried don't work +// for one reason or another. + +namespace permit_forbidden_function { +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS + +[[noreturn]] inline void exit(int status) { ::exit(status); } +[[noreturn]] inline void _exit(int status) { ::_exit(status); } + +ATTRIBUTE_PRINTF(3, 0) +inline int vsnprintf(char* str, size_t size, const char* format, va_list ap) { + return ::vsnprintf(str, size, format, ap); +} + +inline void* malloc(size_t size) { return ::malloc(size); } +inline void free(void* ptr) { return ::free(ptr); } +inline void* calloc(size_t nmemb, size_t size) { return ::calloc(nmemb, size); } +inline void* realloc(void* ptr, size_t size) { return ::realloc(ptr, size); } + +inline char* strdup(const char* s) { return ::strdup(s); } + +END_ALLOW_FORBIDDEN_FUNCTIONS +} // namespace permit_forbidden_function + +#endif // SHARE_UTILITIES_PERMITFORBIDDENFUNCTIONS_HPP diff --git a/test/hotspot/gtest/code/test_codestrings.cpp b/test/hotspot/gtest/code/test_codestrings.cpp index 27f4fdd54e3..46a8ff12f08 100644 --- a/test/hotspot/gtest/code/test_codestrings.cpp +++ b/test/hotspot/gtest/code/test_codestrings.cpp @@ -28,9 +28,12 @@ #include "asm/macroAssembler.inline.hpp" #include "compiler/disassembler.hpp" #include "memory/resourceArea.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/vmassert_uninstall.hpp" +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS #include +END_ALLOW_FORBIDDEN_FUNCTIONS #include "utilities/vmassert_reinstall.hpp" #include "unittest.hpp" diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp index 755e40cfcef..c7077271b5c 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahNumberSeq.cpp @@ -26,7 +26,9 @@ #include "utilities/ostream.hpp" #include "utilities/vmassert_uninstall.hpp" +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS #include +END_ALLOW_FORBIDDEN_FUNCTIONS #include "utilities/vmassert_reinstall.hpp" #include "unittest.hpp" diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp index cf43692ffbb..45d6cf47fe0 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahSimpleBitMap.cpp @@ -23,10 +23,12 @@ #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" #include "gc/shenandoah/shenandoahSimpleBitMap.inline.hpp" - -#include #include "utilities/ostream.hpp" + #include "utilities/vmassert_uninstall.hpp" +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS +#include +END_ALLOW_FORBIDDEN_FUNCTIONS #include "utilities/vmassert_reinstall.hpp" #include "unittest.hpp" diff --git a/test/hotspot/gtest/gtestMain.cpp b/test/hotspot/gtest/gtestMain.cpp index 87531d41164..c593f8dbb19 100644 --- a/test/hotspot/gtest/gtestMain.cpp +++ b/test/hotspot/gtest/gtestMain.cpp @@ -26,6 +26,7 @@ #include "runtime/os.hpp" #include "runtime/thread.inline.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "unittest.hpp" #include @@ -192,7 +193,7 @@ static int num_args_to_skip(char* arg) { static char** remove_test_runner_arguments(int* argcp, char **argv) { int argc = *argcp; - ALLOW_C_FUNCTION(::malloc, char** new_argv = (char**) malloc(sizeof(char*) * argc);) + char** new_argv = (char**)permit_forbidden_function::malloc(sizeof(char*) * argc); int new_argc = 0; int i = 0; @@ -288,7 +289,7 @@ static void runUnitTestsInner(int argc, char** argv) { int result = RUN_ALL_TESTS(); - ALLOW_C_FUNCTION(::free, ::free(argv);) + permit_forbidden_function::free(argv); // vm_assert and other_vm tests never reach this point as they either abort, or call // exit() - see TEST_OTHER_VM macro. We will reach here when all same_vm tests have diff --git a/test/hotspot/gtest/unittest.hpp b/test/hotspot/gtest/unittest.hpp index c6ec593733c..336a2f0766e 100644 --- a/test/hotspot/gtest/unittest.hpp +++ b/test/hotspot/gtest/unittest.hpp @@ -24,6 +24,8 @@ #ifndef UNITTEST_HPP #define UNITTEST_HPP +#include "utilities/globalDefinitions.hpp" + #include #include @@ -49,8 +51,10 @@ #undef F2 #include "utilities/vmassert_uninstall.hpp" +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS #include "gmock/gmock.h" #include "gtest/gtest.h" +END_ALLOW_FORBIDDEN_FUNCTIONS #include "utilities/vmassert_reinstall.hpp" #ifdef UNDEFINED_Log From 1ec64811a365442c902e334b56f4cf926c316a4a Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Thu, 24 Apr 2025 12:01:34 +0000 Subject: [PATCH 007/118] 8350582: Correct the parsing of the ssl value in javax.net.debug Reviewed-by: wetmore, hchao --- .../classes/sun/security/ssl/SSLLogger.java | 8 +- .../SSLLogger/DebugPropertyValuesTest.java | 185 ++++++++++++++++++ 2 files changed, 190 insertions(+), 3 deletions(-) create mode 100644 test/jdk/sun/security/ssl/SSLLogger/DebugPropertyValuesTest.java diff --git a/src/java.base/share/classes/sun/security/ssl/SSLLogger.java b/src/java.base/share/classes/sun/security/ssl/SSLLogger.java index 9736bfaba0d..ec5dee26cfc 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLLogger.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -142,8 +142,10 @@ private static boolean hasOption(String option) { if (property.contains("all")) { return true; } else { - int offset = property.indexOf("ssl"); - if (offset != -1 && property.indexOf("sslctx", offset) != -1) { + // remove first occurrence of "sslctx" since + // it interferes with search for "ssl" + String modified = property.replaceFirst("sslctx", ""); + if (modified.contains("ssl")) { // don't enable data and plaintext options by default if (!(option.equals("data") || option.equals("packet") diff --git a/test/jdk/sun/security/ssl/SSLLogger/DebugPropertyValuesTest.java b/test/jdk/sun/security/ssl/SSLLogger/DebugPropertyValuesTest.java new file mode 100644 index 00000000000..c9ad335a45e --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLLogger/DebugPropertyValuesTest.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8350582 + * @library /test/lib /javax/net/ssl/templates + * @summary Correct the parsing of the ssl value in javax.net.debug + * @run junit DebugPropertyValuesTest + */ + +// A test to verify debug output for different javax.net.debug scenarios + +import jdk.test.lib.process.ProcessTools; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Stream; + +import jdk.test.lib.process.OutputAnalyzer; + +public class DebugPropertyValuesTest extends SSLSocketTemplate { + + private static final Path LOG_FILE = Path.of("logging.conf"); + private static final HashMap> debugMessages = new HashMap<>(); + + static { + debugMessages.put("handshake", + List.of("Produced ClientHello handshake message", + "supported_versions")); + debugMessages.put("keymanager", List.of("choosing key:")); + debugMessages.put("packet", List.of("Raw write")); + debugMessages.put("plaintext", List.of("Plaintext before ENCRYPTION")); + debugMessages.put("record", List.of("handshake, length =", "WRITE:")); + debugMessages.put("session", List.of("Session initialized:")); + debugMessages.put("sslctx", List.of("trigger seeding of SecureRandom")); + debugMessages.put("ssl", List.of("jdk.tls.keyLimits:")); + debugMessages.put("trustmanager", List.of("adding as trusted certificates")); + debugMessages.put("verbose", List.of("Ignore unsupported cipher suite:")); + debugMessages.put("handshake-expand", + List.of("\"logger\".*: \"javax.net.ssl\",", + "\"message\".*: \"Produced ClientHello handshake message")); + debugMessages.put("record-expand", + List.of("\"logger\".*: \"javax.net.ssl\",", + "\"message\".*: \"READ: TLSv1.2 application_data")); + debugMessages.put("help", + List.of("print the help messages", + "debugging can be widened with:")); + debugMessages.put("javax.net.debug", + List.of("properties: Initial security property:", + "certpath: Cert path validation succeeded")); + debugMessages.put("logger", + List.of("FINE: adding as trusted certificates", + "FINE: WRITE: TLSv1.3 application_data")); + } + + @BeforeAll + static void setup() throws Exception { + Files.writeString(LOG_FILE, ".level = ALL\n" + + "handlers= java.util.logging.ConsoleHandler\n" + + "java.util.logging.ConsoleHandler.level = ALL\n"); + } + + private static Stream patternMatches() { + return Stream.of( + // all should print everything + Arguments.of(List.of("-Djavax.net.debug=all"), + List.of("handshake", "keymanager", "packet", + "plaintext", "record", "session", "ssl", + "sslctx", "trustmanager", "verbose")), + // ssl should print most details except verbose details + Arguments.of(List.of("-Djavax.net.debug=ssl"), + List.of("handshake", "keymanager", + "record", "session", "ssl", + "sslctx", "trustmanager", "verbose")), + // allow expand option for more verbose output + Arguments.of(List.of("-Djavax.net.debug=ssl,handshake,expand"), + List.of("handshake", "handshake-expand", "keymanager", + "record", "session", "record-expand", "ssl", + "sslctx", "trustmanager", "verbose")), + // filtering on record option, with expand + Arguments.of(List.of("-Djavax.net.debug=ssl:record,expand"), + List.of("handshake", "handshake-expand", "keymanager", + "record", "record-expand", "session", "ssl", + "sslctx", "trustmanager", "verbose")), + // this test is equivalent to ssl:record mode + Arguments.of(List.of("-Djavax.net.debug=ssl,record"), + List.of("handshake", "keymanager", "record", + "session", "ssl", "sslctx", + "trustmanager", "verbose")), + // example of test where no "ssl" value is passed + // handshake debugging with verbose mode + // only verbose gets printed. Needs fixing (JDK-8044609) + Arguments.of(List.of("-Djavax.net.debug=handshake:verbose"), + List.of("verbose")), + // another example of test where no "ssl" value is passed + Arguments.of(List.of("-Djavax.net.debug=record"), + List.of("record")), + // ignore bad sub-option. treat like "ssl" + Arguments.of(List.of("-Djavax.net.debug=ssl,typo"), + List.of("handshake", "keymanager", + "record", "session", "ssl", + "sslctx", "trustmanager", "verbose")), + // ssltypo contains "ssl". Treat like "ssl" + Arguments.of(List.of("-Djavax.net.debug=ssltypo"), + List.of("handshake", "keymanager", + "record", "session", "ssl", + "sslctx", "trustmanager", "verbose")), + // plaintext is valid for record option + Arguments.of(List.of("-Djavax.net.debug=ssl:record:plaintext"), + List.of("handshake", "keymanager", "plaintext", + "record", "session", "ssl", + "sslctx", "trustmanager", "verbose")), + Arguments.of(List.of("-Djavax.net.debug=ssl:trustmanager"), + List.of("handshake", "keymanager", "record", "session", + "ssl", "sslctx", "trustmanager", "verbose")), + Arguments.of(List.of("-Djavax.net.debug=ssl:sslctx"), + List.of("handshake", "keymanager", "record", "session", + "ssl", "sslctx", "trustmanager", "verbose")), + // help message test. Should exit without running test + Arguments.of(List.of("-Djavax.net.debug=help"), + List.of("help")), + // add in javax.net.debug sanity test + Arguments.of(List.of("-Djavax.net.debug=ssl:trustmanager", + "-Djava.security.debug=all"), + List.of("handshake", "javax.net.debug", "keymanager", + "record", "session", "ssl", "sslctx", + "trustmanager", "verbose")), + // empty invokes System.Logger use + Arguments.of(List.of("-Djavax.net.debug", + "-Djava.util.logging.config.file=" + LOG_FILE), + List.of("handshake", "keymanager", "logger", "packet", + "plaintext", "record", "session", "ssl", + "sslctx", "trustmanager", "verbose")) + ); + } + + @ParameterizedTest + @MethodSource("patternMatches") + public void checkDebugOutput(List params, + List expected) throws Exception { + + List args = new ArrayList<>(params); + args.add("DebugPropertyValuesTest"); + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava(args); + outputAnalyzer.shouldHaveExitValue(0); + for (String s : debugMessages.keySet()) { + for (String output : debugMessages.get(s)) { + if (expected.contains(s)) { + outputAnalyzer.shouldMatch(output); + } else { + outputAnalyzer.shouldNotMatch(output); + } + } + } + } +} From 34c4d895ca321508c24b13338900d617679aadae Mon Sep 17 00:00:00 2001 From: Oleksii Sylichenko Date: Thu, 24 Apr 2025 12:50:03 +0000 Subject: [PATCH 008/118] 8353190: Use "/native" Run Option for TestAvailableProcessors Execution Reviewed-by: dholmes --- .../os/windows/TestAvailableProcessors.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java b/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java index f7dc237d07d..795b3d76e54 100644 --- a/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java +++ b/test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,18 +31,14 @@ * @requires vm.flagless * @library /test/lib * @compile GetAvailableProcessors.java - * @run testng TestAvailableProcessors + * @run testng/othervm/native TestAvailableProcessors */ import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; import java.util.List; import java.util.HashSet; import java.util.Set; -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -172,12 +168,8 @@ private static void verifyAvailableProcessorsWithEnabledProductFlag(boolean sche @Test private static void testProcessorAvailability() throws IOException { - // Launch GetProcessorInfo.exe to gather processor counts - Path nativeGetProcessorInfo = Paths.get(Utils.TEST_NATIVE_PATH) - .resolve("GetProcessorInfo.exe") - .toAbsolutePath(); - - var processBuilder = new ProcessBuilder(nativeGetProcessorInfo.toString()); + // Launch "/GetProcessorInfo.exe" to gather processor counts + var processBuilder = new ProcessBuilder("GetProcessorInfo.exe"); var outputAnalyzer= new OutputAnalyzer(processBuilder.start()); outputAnalyzer.shouldHaveExitValue(0); outputAnalyzer.shouldContain(totalProcessorCountMessage); From 0537c6927d4f617624672cfae06928f9738175ca Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 24 Apr 2025 13:39:43 +0000 Subject: [PATCH 009/118] 8355492: MissedOptCastII is missing UnlockDiagnosticVMOptions flag Reviewed-by: rcastanedalo, chagedorn, thartmann --- test/hotspot/jtreg/compiler/c2/gvn/MissedOptCastII.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/compiler/c2/gvn/MissedOptCastII.java b/test/hotspot/jtreg/compiler/c2/gvn/MissedOptCastII.java index a32fa020065..5cd83cbe09a 100644 --- a/test/hotspot/jtreg/compiler/c2/gvn/MissedOptCastII.java +++ b/test/hotspot/jtreg/compiler/c2/gvn/MissedOptCastII.java @@ -32,6 +32,7 @@ * -XX:CompileCommand=compileonly,MissedOptCastII::* * -XX:-TieredCompilation -Xcomp * -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions * -XX:+StressIGVN -XX:VerifyIterativeGVN=10 * MissedOptCastII */ From cf96b107d57182ad6ab47125939423dd5286aa88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Thu, 24 Apr 2025 14:14:10 +0000 Subject: [PATCH 010/118] 8354362: Use automatic indentation in CollectedHeap printing Reviewed-by: stefank, lkorinth, stuefe --- src/hotspot/share/gc/epsilon/epsilonHeap.cpp | 19 ++--- src/hotspot/share/gc/epsilon/epsilonHeap.hpp | 4 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 20 +++-- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 4 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 4 +- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 4 +- .../share/gc/parallel/mutableNUMASpace.cpp | 13 +-- .../share/gc/parallel/mutableNUMASpace.hpp | 4 +- .../share/gc/parallel/mutableSpace.cpp | 7 +- .../share/gc/parallel/mutableSpace.hpp | 4 +- .../share/gc/parallel/parMarkBitMap.hpp | 8 +- .../gc/parallel/parallelScavengeHeap.cpp | 12 +-- .../gc/parallel/parallelScavengeHeap.hpp | 6 +- src/hotspot/share/gc/parallel/psOldGen.cpp | 15 ++-- .../share/gc/parallel/psParallelCompact.cpp | 4 +- .../share/gc/parallel/psParallelCompact.hpp | 4 +- .../share/gc/parallel/psVirtualspace.cpp | 2 +- src/hotspot/share/gc/parallel/psYoungGen.cpp | 13 +-- .../share/gc/serial/defNewGeneration.cpp | 24 ++---- src/hotspot/share/gc/serial/serialHeap.cpp | 9 +- src/hotspot/share/gc/serial/serialHeap.hpp | 4 +- .../share/gc/serial/tenuredGeneration.cpp | 13 ++- src/hotspot/share/gc/shared/collectedHeap.cpp | 26 ++++-- src/hotspot/share/gc/shared/collectedHeap.hpp | 12 +-- src/hotspot/share/gc/shared/markBitMap.cpp | 4 +- src/hotspot/share/gc/shared/markBitMap.hpp | 4 +- src/hotspot/share/gc/shared/space.cpp | 7 +- src/hotspot/share/gc/shared/space.hpp | 4 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 7 +- .../share/gc/shenandoah/shenandoahHeap.hpp | 4 +- src/hotspot/share/gc/z/zCollectedHeap.cpp | 12 +-- src/hotspot/share/gc/z/zCollectedHeap.hpp | 4 +- src/hotspot/share/gc/z/zHeap.cpp | 35 +++----- src/hotspot/share/gc/z/zHeap.hpp | 4 +- src/hotspot/share/gc/z/zMappedCache.cpp | 7 +- src/hotspot/share/gc/z/zPageAllocator.cpp | 85 +++++++++---------- src/hotspot/share/gc/z/zPageAllocator.hpp | 11 ++- src/hotspot/share/memory/metaspace.cpp | 14 +-- src/hotspot/share/memory/universe.cpp | 5 +- src/hotspot/share/memory/virtualspace.cpp | 19 +++-- src/hotspot/share/memory/virtualspace.hpp | 4 +- .../share/services/diagnosticCommand.cpp | 4 +- src/hotspot/share/utilities/bitMap.cpp | 2 +- src/hotspot/share/utilities/bitMap.hpp | 2 +- src/hotspot/share/utilities/ostream.hpp | 12 +-- src/hotspot/share/utilities/vmError.cpp | 44 +++++++--- 46 files changed, 270 insertions(+), 259 deletions(-) diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp index d5ee7835fea..c3d3af26528 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp @@ -37,6 +37,7 @@ #include "memory/universe.hpp" #include "runtime/atomic.hpp" #include "runtime/globals.hpp" +#include "utilities/ostream.hpp" jint EpsilonHeap::initialize() { size_t align = HeapAlignment; @@ -297,26 +298,18 @@ void EpsilonHeap::object_iterate(ObjectClosure *cl) { _space->object_iterate(cl); } -void EpsilonHeap::print_on(outputStream *st) const { +void EpsilonHeap::print_heap_on(outputStream *st) const { st->print_cr("Epsilon Heap"); + StreamAutoIndentor indentor(st, 1); + _virtual_space.print_on(st); if (_space != nullptr) { st->print_cr("Allocation space:"); - _space->print_on(st); - } - - MetaspaceUtils::print_on(st); -} - -void EpsilonHeap::print_on_error(outputStream *st) const { - print_on(st); - st->cr(); - BarrierSet* bs = BarrierSet::barrier_set(); - if (bs != nullptr) { - bs->print_on(st); + StreamAutoIndentor indentor(st, 1); + _space->print_on(st, ""); } } diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp index 81bcd61916f..129e81c1c34 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp @@ -131,8 +131,8 @@ class EpsilonHeap : public CollectedHeap { bool can_load_archived_objects() const override { return true; } HeapWord* allocate_loaded_archive_space(size_t size) override; - void print_on(outputStream* st) const override; - void print_on_error(outputStream* st) const override; + void print_heap_on(outputStream* st) const override; + void print_gc_on(outputStream* st) const override {} void print_tracing_info() const override; bool print_location(outputStream* st, void* addr) const override; diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 8b36bf124f2..4ce45d06d1d 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2112,16 +2112,18 @@ void G1CollectedHeap::print_heap_regions() const { } } -void G1CollectedHeap::print_on(outputStream* st) const { +void G1CollectedHeap::print_heap_on(outputStream* st) const { size_t heap_used = Heap_lock->owned_by_self() ? used() : used_unlocked(); - st->print(" %-20s", "garbage-first heap"); + st->print("%-20s", "garbage-first heap"); st->print(" total reserved %zuK, committed %zuK, used %zuK", _hrm.reserved().byte_size()/K, capacity()/K, heap_used/K); st->print(" [" PTR_FORMAT ", " PTR_FORMAT ")", p2i(_hrm.reserved().start()), p2i(_hrm.reserved().end())); st->cr(); - st->print(" region size %zuK, ", G1HeapRegion::GrainBytes / K); + + StreamAutoIndentor indentor(st, 1); + st->print("region size %zuK, ", G1HeapRegion::GrainBytes / K); uint young_regions = young_regions_count(); st->print("%u young (%zuK), ", young_regions, (size_t) young_regions * G1HeapRegion::GrainBytes / K); @@ -2131,7 +2133,7 @@ void G1CollectedHeap::print_on(outputStream* st) const { st->cr(); if (_numa->is_enabled()) { uint num_nodes = _numa->num_active_nodes(); - st->print(" remaining free region(s) on each NUMA node: "); + st->print("remaining free region(s) on each NUMA node: "); const uint* node_ids = _numa->node_ids(); for (uint node_index = 0; node_index < num_nodes; node_index++) { uint num_free_regions = _hrm.num_free_regions(node_index); @@ -2139,7 +2141,6 @@ void G1CollectedHeap::print_on(outputStream* st) const { } st->cr(); } - MetaspaceUtils::print_on(st); } void G1CollectedHeap::print_regions_on(outputStream* st) const { @@ -2153,15 +2154,16 @@ void G1CollectedHeap::print_regions_on(outputStream* st) const { } void G1CollectedHeap::print_extended_on(outputStream* st) const { - print_on(st); + print_heap_on(st); // Print the per-region information. st->cr(); print_regions_on(st); } -void G1CollectedHeap::print_on_error(outputStream* st) const { - print_extended_on(st); +void G1CollectedHeap::print_gc_on(outputStream* st) const { + // Print the per-region information. + print_regions_on(st); st->cr(); BarrierSet* bs = BarrierSet::barrier_set(); @@ -2171,7 +2173,7 @@ void G1CollectedHeap::print_on_error(outputStream* st) const { if (_cm != nullptr) { st->cr(); - _cm->print_on_error(st); + _cm->print_on(st); } } diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 0f583e8dcbf..92e08e6fc61 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -1312,9 +1312,9 @@ class G1CollectedHeap : public CollectedHeap { void print_regions_on(outputStream* st) const; public: - void print_on(outputStream* st) const override; + void print_heap_on(outputStream* st) const override; void print_extended_on(outputStream* st) const; - void print_on_error(outputStream* st) const override; + void print_gc_on(outputStream* st) const override; void gc_threads_do(ThreadClosure* tc) const override; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index ef62587d868..07b5afcf987 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -2126,9 +2126,9 @@ void G1ConcurrentMark::threads_do(ThreadClosure* tc) const { _concurrent_workers->threads_do(tc); } -void G1ConcurrentMark::print_on_error(outputStream* st) const { +void G1ConcurrentMark::print_on(outputStream* st) const { st->print_cr("Marking Bits: (CMBitMap*) " PTR_FORMAT, p2i(mark_bitmap())); - _mark_bitmap.print_on_error(st, " Bits: "); + _mark_bitmap.print_on(st, " Bits: "); } static ReferenceProcessor* get_cm_oop_closure_ref_processor(G1CollectedHeap* g1h) { diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 2fb9732b88e..a4c2e94b2b1 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -707,7 +707,7 @@ class G1ConcurrentMark : public CHeapObj { void threads_do(ThreadClosure* tc) const; - void print_on_error(outputStream* st) const; + void print_on(outputStream* st) const; // Mark the given object on the marking bitmap if it is below TAMS. inline bool mark_in_bitmap(uint worker_id, oop const obj); diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp index 874d3974ead..abc0d7baa64 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp @@ -608,17 +608,20 @@ void MutableNUMASpace::print_short_on(outputStream* st) const { st->print(")"); } -void MutableNUMASpace::print_on(outputStream* st) const { - MutableSpace::print_on(st); +void MutableNUMASpace::print_on(outputStream* st, const char* prefix) const { + MutableSpace::print_on(st, prefix); + + StreamAutoIndentor indentor(st, 1); for (int i = 0; i < lgrp_spaces()->length(); i++) { LGRPSpace *ls = lgrp_spaces()->at(i); - st->print(" lgrp %u", ls->lgrp_id()); - ls->space()->print_on(st); + FormatBuffer<128> lgrp_message("lgrp %u ", ls->lgrp_id()); + ls->space()->print_on(st, lgrp_message); if (NUMAStats) { + StreamAutoIndentor indentor_numa(st, 1); for (int i = 0; i < lgrp_spaces()->length(); i++) { lgrp_spaces()->at(i)->accumulate_statistics(page_size()); } - st->print(" local/remote/unbiased/uncommitted: %zuK/" + st->print("local/remote/unbiased/uncommitted: %zuK/" "%zuK/%zuK/%zuK\n", ls->space_stats()->_local_space / K, ls->space_stats()->_remote_space / K, diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp index 10ca66e3549..abb4c77952a 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -186,7 +186,7 @@ class MutableNUMASpace : public MutableSpace { virtual HeapWord* cas_allocate(size_t word_size); // Debugging - virtual void print_on(outputStream* st) const; + virtual void print_on(outputStream* st, const char* prefix) const; virtual void print_short_on(outputStream* st) const; virtual void verify(); diff --git a/src/hotspot/share/gc/parallel/mutableSpace.cpp b/src/hotspot/share/gc/parallel/mutableSpace.cpp index 19ec0fcf839..498fb12511c 100644 --- a/src/hotspot/share/gc/parallel/mutableSpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableSpace.cpp @@ -232,12 +232,13 @@ void MutableSpace::object_iterate(ObjectClosure* cl) { void MutableSpace::print_short() const { print_short_on(tty); } void MutableSpace::print_short_on( outputStream* st) const { - st->print(" space %zuK, %d%% used", capacity_in_bytes() / K, + st->print("space %zuK, %d%% used", capacity_in_bytes() / K, (int) ((double) used_in_bytes() * 100 / capacity_in_bytes())); } -void MutableSpace::print() const { print_on(tty); } -void MutableSpace::print_on(outputStream* st) const { +void MutableSpace::print() const { print_on(tty, ""); } +void MutableSpace::print_on(outputStream* st, const char* prefix) const { + st->print("%s", prefix); MutableSpace::print_short_on(st); st->print_cr(" [" PTR_FORMAT "," PTR_FORMAT "," PTR_FORMAT ")", p2i(bottom()), p2i(top()), p2i(end())); diff --git a/src/hotspot/share/gc/parallel/mutableSpace.hpp b/src/hotspot/share/gc/parallel/mutableSpace.hpp index 4583be0e1ea..d09a2b2df89 100644 --- a/src/hotspot/share/gc/parallel/mutableSpace.hpp +++ b/src/hotspot/share/gc/parallel/mutableSpace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,7 +138,7 @@ class MutableSpace: public CHeapObj { // Debugging virtual void print() const; - virtual void print_on(outputStream* st) const; + virtual void print_on(outputStream* st, const char* prefix) const; virtual void print_short() const; virtual void print_short_on(outputStream* st) const; virtual void verify(); diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp index 4c3cc39edec..aa788ff7be0 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,9 +58,11 @@ class ParMarkBitMap: public CHeapObj { // Clear a range of bits corresponding to heap address range [beg, end). inline void clear_range(HeapWord* beg, HeapWord* end); - void print_on_error(outputStream* st) const { + void print_on(outputStream* st) const { st->print_cr("Marking Bits: (ParMarkBitMap*) " PTR_FORMAT, p2i(this)); - _beg_bits.print_on_error(st, " Begin Bits: "); + + StreamAutoIndentor indentor(st, 1); + _beg_bits.print_range_on(st, "Begin Bits: "); } #ifdef ASSERT diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 244094f1acc..0e63d760f48 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -662,27 +662,23 @@ bool ParallelScavengeHeap::print_location(outputStream* st, void* addr) const { return BlockLocationPrinter::print_location(st, addr); } -void ParallelScavengeHeap::print_on(outputStream* st) const { +void ParallelScavengeHeap::print_heap_on(outputStream* st) const { if (young_gen() != nullptr) { young_gen()->print_on(st); } if (old_gen() != nullptr) { old_gen()->print_on(st); } - MetaspaceUtils::print_on(st); } -void ParallelScavengeHeap::print_on_error(outputStream* st) const { - print_on(st); - st->cr(); - +void ParallelScavengeHeap::print_gc_on(outputStream* st) const { BarrierSet* bs = BarrierSet::barrier_set(); if (bs != nullptr) { bs->print_on(st); } - st->cr(); - PSParallelCompact::print_on_error(st); + + PSParallelCompact::print_on(st); } void ParallelScavengeHeap::gc_threads_do(ThreadClosure* tc) const { diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index ef9a4b4d5a1..887b78758cf 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -214,8 +214,8 @@ class ParallelScavengeHeap : public CollectedHeap { void prepare_for_verify() override; PSHeapSummary create_ps_heap_summary(); - void print_on(outputStream* st) const override; - void print_on_error(outputStream* st) const override; + void print_heap_on(outputStream* st) const override; + void print_gc_on(outputStream* st) const override; void gc_threads_do(ThreadClosure* tc) const override; void print_tracing_info() const override; diff --git a/src/hotspot/share/gc/parallel/psOldGen.cpp b/src/hotspot/share/gc/parallel/psOldGen.cpp index fc3f7df926f..3bf125bc295 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.cpp +++ b/src/hotspot/share/gc/parallel/psOldGen.cpp @@ -358,15 +358,12 @@ void PSOldGen::post_resize() { void PSOldGen::print() const { print_on(tty);} void PSOldGen::print_on(outputStream* st) const { - st->print(" %-15s", name()); - st->print(" total %zuK, used %zuK", - capacity_in_bytes()/K, used_in_bytes()/K); - st->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", - p2i(virtual_space()->low_boundary()), - p2i(virtual_space()->high()), - p2i(virtual_space()->high_boundary())); - - st->print(" object"); object_space()->print_on(st); + st->print("%-15s", name()); + st->print(" total %zuK, used %zuK ", capacity_in_bytes() / K, used_in_bytes() / K); + virtual_space()->print_space_boundaries_on(st); + + StreamAutoIndentor indentor(st, 1); + object_space()->print_on(st, "object "); } void PSOldGen::update_counters() { diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 99b975c282a..e63ff686312 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -210,8 +210,8 @@ void SplitInfo::verify_clear() #endif // #ifdef ASSERT -void PSParallelCompact::print_on_error(outputStream* st) { - _mark_bitmap.print_on_error(st); +void PSParallelCompact::print_on(outputStream* st) { + _mark_bitmap.print_on(st); } ParallelCompactData::ParallelCompactData() : diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 878a09e283b..290dd809ddd 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -846,7 +846,7 @@ class PSParallelCompact : AllStatic { // Return the SpaceId for the given address. static SpaceId space_id(HeapWord* addr); - static void print_on_error(outputStream* st); + static void print_on(outputStream* st); #ifdef ASSERT // Sanity check the new location of a word in the heap. diff --git a/src/hotspot/share/gc/parallel/psVirtualspace.cpp b/src/hotspot/share/gc/parallel/psVirtualspace.cpp index ce4cd4ad977..b15264f5fca 100644 --- a/src/hotspot/share/gc/parallel/psVirtualspace.cpp +++ b/src/hotspot/share/gc/parallel/psVirtualspace.cpp @@ -124,6 +124,6 @@ void PSVirtualSpace::verify() const { #endif // #ifndef PRODUCT void PSVirtualSpace::print_space_boundaries_on(outputStream* st) const { - st->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", + st->print_cr("[" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", p2i(low_boundary()), p2i(high()), p2i(high_boundary())); } diff --git a/src/hotspot/share/gc/parallel/psYoungGen.cpp b/src/hotspot/share/gc/parallel/psYoungGen.cpp index 309b293e5ac..cf21e45da9e 100644 --- a/src/hotspot/share/gc/parallel/psYoungGen.cpp +++ b/src/hotspot/share/gc/parallel/psYoungGen.cpp @@ -700,13 +700,14 @@ void PSYoungGen::object_iterate(ObjectClosure* blk) { void PSYoungGen::print() const { print_on(tty); } void PSYoungGen::print_on(outputStream* st) const { - st->print(" %-15s", "PSYoungGen"); - st->print(" total %zuK, used %zuK", - capacity_in_bytes()/K, used_in_bytes()/K); + st->print("%-15s", name()); + st->print(" total %zuK, used %zuK ", capacity_in_bytes() / K, used_in_bytes() / K); virtual_space()->print_space_boundaries_on(st); - st->print(" eden"); eden_space()->print_on(st); - st->print(" from"); from_space()->print_on(st); - st->print(" to "); to_space()->print_on(st); + + StreamAutoIndentor indentor(st, 1); + eden_space()->print_on(st, "eden "); + from_space()->print_on(st, "from "); + to_space()->print_on(st, "to "); } size_t PSYoungGen::available_to_min_gen() { diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 8ad42bc702d..cebfa743eac 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -825,21 +825,15 @@ void DefNewGeneration::verify() { } void DefNewGeneration::print_on(outputStream* st) const { - st->print(" %-10s", name()); - - st->print(" total %zuK, used %zuK", - capacity()/K, used()/K); - st->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", - p2i(_virtual_space.low_boundary()), - p2i(_virtual_space.high()), - p2i(_virtual_space.high_boundary())); - - st->print(" eden"); - eden()->print_on(st); - st->print(" from"); - from()->print_on(st); - st->print(" to "); - to()->print_on(st); + st->print("%-10s", name()); + + st->print(" total %zuK, used %zuK ", capacity() / K, used() / K); + _virtual_space.print_space_boundaries_on(st); + + StreamAutoIndentor indentor(st, 1); + eden()->print_on(st, "eden "); + from()->print_on(st, "from "); + to()->print_on(st, "to "); } HeapWord* DefNewGeneration::allocate(size_t word_size) { diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index ea2b656d4bd..8d922692e59 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -800,20 +800,15 @@ void SerialHeap::verify(VerifyOption option /* ignored */) { rem_set()->verify(); } -void SerialHeap::print_on(outputStream* st) const { +void SerialHeap::print_heap_on(outputStream* st) const { assert(_young_gen != nullptr, "precondition"); assert(_old_gen != nullptr, "precondition"); _young_gen->print_on(st); _old_gen->print_on(st); - - MetaspaceUtils::print_on(st); } -void SerialHeap::print_on_error(outputStream* st) const { - print_on(st); - st->cr(); - +void SerialHeap::print_gc_on(outputStream* st) const { BarrierSet* bs = BarrierSet::barrier_set(); if (bs != nullptr) { bs->print_on(st); diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index 2ec50814daf..30b7b9a0085 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -206,8 +206,8 @@ class SerialHeap : public CollectedHeap { void prepare_for_verify() override; void verify(VerifyOption option) override; - void print_on(outputStream* st) const override; - void print_on_error(outputStream* st) const override; + void print_heap_on(outputStream* st) const override; + void print_gc_on(outputStream* st) const override; void gc_threads_do(ThreadClosure* tc) const override; void print_tracing_info() const override; diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index 22c4808a0bd..975b0b5f98a 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -439,15 +439,12 @@ void TenuredGeneration::verify() { } void TenuredGeneration::print_on(outputStream* st) const { - st->print(" %-10s", name()); + st->print("%-10s", name()); - st->print(" total %zuK, used %zuK", + st->print(" total %zuK, used %zuK ", capacity()/K, used()/K); - st->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", - p2i(_virtual_space.low_boundary()), - p2i(_virtual_space.high()), - p2i(_virtual_space.high_boundary())); + _virtual_space.print_space_boundaries_on(st); - st->print(" the"); - _the_space->print_on(st); + StreamAutoIndentor indentor(st, 1); + _the_space->print_on(st, "the "); } diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index ec9872bf402..f0b90edeb79 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -45,7 +45,6 @@ #include "memory/metaspace.hpp" #include "memory/metaspaceUtils.hpp" #include "memory/reservedSpace.hpp" -#include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/oop.inline.hpp" @@ -59,6 +58,7 @@ #include "utilities/align.hpp" #include "utilities/copy.hpp" #include "utilities/events.hpp" +#include "utilities/ostream.hpp" class ClassLoaderData; @@ -111,7 +111,12 @@ void GCHeapLog::log_heap(CollectedHeap* heap, bool before) { heap->total_collections(), heap->total_full_collections()); - heap->print_on(&st); + { + StreamAutoIndentor indentor(&st, 1); + heap->print_heap_on(&st); + MetaspaceUtils::print_on(&st); + } + st.print_cr("}"); } @@ -163,8 +168,10 @@ void CollectedHeap::print_heap_before_gc() { if (lt.is_enabled()) { LogStream ls(lt); ls.print_cr("Heap before GC invocations=%u (full %u):", total_collections(), total_full_collections()); - ResourceMark rm; - print_on(&ls); + + StreamAutoIndentor indentor(&ls, 1); + print_heap_on(&ls); + MetaspaceUtils::print_on(&ls); } if (_gc_heap_log != nullptr) { @@ -177,8 +184,10 @@ void CollectedHeap::print_heap_after_gc() { if (lt.is_enabled()) { LogStream ls(lt); ls.print_cr("Heap after GC invocations=%u (full %u):", total_collections(), total_full_collections()); - ResourceMark rm; - print_on(&ls); + + StreamAutoIndentor indentor(&ls, 1); + print_heap_on(&ls); + MetaspaceUtils::print_on(&ls); } if (_gc_heap_log != nullptr) { @@ -186,7 +195,10 @@ void CollectedHeap::print_heap_after_gc() { } } -void CollectedHeap::print() const { print_on(tty); } +void CollectedHeap::print() const { + print_heap_on(tty); + print_gc_on(tty); +} void CollectedHeap::trace_heap(GCWhen::Type when, const GCTracer* gc_tracer) { const GCHeapSummary& heap_summary = create_heap_summary(); diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 7b3fbd1a1c4..439563a4b62 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -435,12 +435,14 @@ class CollectedHeap : public CHeapObj { // explicitly checks if the given memory location contains a null value. virtual bool contains_null(const oop* p) const; - // Print heap information on the given outputStream. - virtual void print_on(outputStream* st) const = 0; - // The default behavior is to call print_on() on tty. - virtual void print() const; + // Print heap information. + virtual void print_heap_on(outputStream* st) const = 0; + + // Print additional information about the GC that is not included in print_heap_on(). + virtual void print_gc_on(outputStream* st) const = 0; - virtual void print_on_error(outputStream* st) const = 0; + // The default behavior is to call print_heap_on() and print_gc_on() on tty. + virtual void print() const; // Used to print information about locations in the hs_err file. virtual bool print_location(outputStream* st, void* addr) const = 0; diff --git a/src/hotspot/share/gc/shared/markBitMap.cpp b/src/hotspot/share/gc/shared/markBitMap.cpp index b2b1e802462..193cc0af4f7 100644 --- a/src/hotspot/share/gc/shared/markBitMap.cpp +++ b/src/hotspot/share/gc/shared/markBitMap.cpp @@ -25,8 +25,8 @@ #include "gc/shared/markBitMap.inline.hpp" #include "memory/universe.hpp" -void MarkBitMap::print_on_error(outputStream* st, const char* prefix) const { - _bm.print_on_error(st, prefix); +void MarkBitMap::print_on(outputStream* st, const char* prefix) const { + _bm.print_range_on(st, prefix); } size_t MarkBitMap::compute_size(size_t heap_size) { diff --git a/src/hotspot/share/gc/shared/markBitMap.hpp b/src/hotspot/share/gc/shared/markBitMap.hpp index adfd9307813..a55a8220910 100644 --- a/src/hotspot/share/gc/shared/markBitMap.hpp +++ b/src/hotspot/share/gc/shared/markBitMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,7 +84,7 @@ class MarkBitMap { inline HeapWord* get_next_marked_addr(const HeapWord* addr, HeapWord* limit) const; - void print_on_error(outputStream* st, const char* prefix) const; + void print_on(outputStream* st, const char* prefix) const; // Write marks. inline void mark(HeapWord* addr); diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 6a9b2b90f44..9256a70adbc 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -76,10 +76,11 @@ void ContiguousSpace::mangle_unused_area(MemRegion mr) { #endif // NOT_PRODUCT -void ContiguousSpace::print() const { print_on(tty); } +void ContiguousSpace::print() const { print_on(tty, ""); } -void ContiguousSpace::print_on(outputStream* st) const { - st->print_cr(" space %zuK, %3d%% used [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", +void ContiguousSpace::print_on(outputStream* st, const char* prefix) const { + st->print_cr("%sspace %zuK, %3d%% used [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", + prefix, capacity() / K, (int) ((double) used() * 100 / capacity()), p2i(bottom()), p2i(top()), p2i(end())); } diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp index 5d361ce8e50..75dd3f998d6 100644 --- a/src/hotspot/share/gc/shared/space.hpp +++ b/src/hotspot/share/gc/shared/space.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,7 +94,7 @@ class ContiguousSpace: public CHeapObj { size_t free() const { return byte_size(top(), end()); } void print() const; - void print_on(outputStream* st) const; + void print_on(outputStream* st, const char* prefix) const; // Initialization. // "initialize" should be called once on a space, before it is used for diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 82c6cdb8971..b5b8e4b9e1a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -583,7 +583,7 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) : #pragma warning( pop ) #endif -void ShenandoahHeap::print_on(outputStream* st) const { +void ShenandoahHeap::print_heap_on(outputStream* st) const { st->print_cr("Shenandoah Heap"); st->print_cr(" %zu%s max, %zu%s soft max, %zu%s committed, %zu%s used", byte_size_in_proper_unit(max_capacity()), proper_unit_for_byte_size(max_capacity()), @@ -634,7 +634,6 @@ void ShenandoahHeap::print_on(outputStream* st) const { } st->cr(); - MetaspaceUtils::print_on(st); if (Verbose) { st->cr(); @@ -642,9 +641,7 @@ void ShenandoahHeap::print_on(outputStream* st) const { } } -void ShenandoahHeap::print_on_error(outputStream* st) const { - print_on(st); - st->cr(); +void ShenandoahHeap::print_gc_on(outputStream* st) const { print_heap_regions_on(st); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 4f24b9e1abd..78d507c0f7d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -202,8 +202,8 @@ class ShenandoahHeap : public CollectedHeap { virtual void print_init_logger() const; void initialize_serviceability() override; - void print_on(outputStream* st) const override; - void print_on_error(outputStream *st) const override; + void print_heap_on(outputStream* st) const override; + void print_gc_on(outputStream *st) const override; void print_tracing_info() const override; void print_heap_regions_on(outputStream* st) const; diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index 642ad42a1d7..a94e50e2a52 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -355,16 +355,12 @@ void ZCollectedHeap::prepare_for_verify() { // Does nothing } -void ZCollectedHeap::print_on(outputStream* st) const { - StreamAutoIndentor auto_indentor(st); - - _heap.print_on(st); +void ZCollectedHeap::print_heap_on(outputStream* st) const { + _heap.print_usage_on(st); } -void ZCollectedHeap::print_on_error(outputStream* st) const { - StreamAutoIndentor auto_indentor(st); - - _heap.print_on_error(st); +void ZCollectedHeap::print_gc_on(outputStream* st) const { + _heap.print_gc_on(st); } void ZCollectedHeap::print_tracing_info() const { diff --git a/src/hotspot/share/gc/z/zCollectedHeap.hpp b/src/hotspot/share/gc/z/zCollectedHeap.hpp index 08aa7d40a3f..9ae3da39dd9 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.hpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.hpp @@ -115,8 +115,8 @@ class ZCollectedHeap : public CollectedHeap { void pin_object(JavaThread* thread, oop obj) override; void unpin_object(JavaThread* thread, oop obj) override; - void print_on(outputStream* st) const override; - void print_on_error(outputStream* st) const override; + void print_heap_on(outputStream* st) const override; + void print_gc_on(outputStream* st) const override; void print_tracing_info() const override; bool print_location(outputStream* st, void* addr) const override; diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 90f8a867135..ddfa5775fb2 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -314,33 +314,18 @@ ZServiceabilityCounters* ZHeap::serviceability_counters() { return _serviceability.counters(); } -void ZHeap::print_on(outputStream* st) const { - streamIndentor indentor(st, 1); - _page_allocator.print_on(st); - - // Metaspace printing prepends spaces instead of using outputStream indentation - streamIndentor indentor_back(st, -1); - MetaspaceUtils::print_on(st); +void ZHeap::print_usage_on(outputStream* st) const { + _page_allocator.print_usage_on(st); } -void ZHeap::print_on_error(outputStream* st) const { - { - streamIndentor indentor(st, 1); - _page_allocator.print_on_error(st); - - // Metaspace printing prepends spaces instead of using outputStream indentation - streamIndentor indentor_back(st, -1); - MetaspaceUtils::print_on(st); - } - st->cr(); - +void ZHeap::print_gc_on(outputStream* st) const { print_globals_on(st); st->cr(); print_page_table_on(st); st->cr(); - _page_allocator.print_extended_on_error(st); + _page_allocator.print_cache_extended_on(st); } void ZHeap::print_globals_on(outputStream* st) const { @@ -373,12 +358,12 @@ void ZHeap::print_page_table_on(outputStream* st) const { // Print all pages st->print_cr("ZGC Page Table:"); - { - streamIndentor indentor(st, 1); - ZPageTableIterator iter(&_page_table); - for (ZPage* page; iter.next(&page);) { - page->print_on(st); - } + + StreamAutoIndentor indentor(st, 1); + + ZPageTableIterator iter(&_page_table); + for (ZPage* page; iter.next(&page);) { + page->print_on(st); } // Allow pages to be deleted diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 823fc009b2c..64be61cc873 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -130,8 +130,8 @@ class ZHeap { ZServiceabilityCounters* serviceability_counters(); // Printing - void print_on(outputStream* st) const; - void print_on_error(outputStream* st) const; + void print_usage_on(outputStream* st) const; + void print_gc_on(outputStream* st) const; void print_globals_on(outputStream* st) const; void print_page_table_on(outputStream* st) const; bool print_location(outputStream* st, uintptr_t addr) const; diff --git a/src/hotspot/share/gc/z/zMappedCache.cpp b/src/hotspot/share/gc/z/zMappedCache.cpp index c1c6e9edee9..f2bea439df2 100644 --- a/src/hotspot/share/gc/z/zMappedCache.cpp +++ b/src/hotspot/share/gc/z/zMappedCache.cpp @@ -30,6 +30,7 @@ #include "utilities/align.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" #include "utilities/powerOfTwo.hpp" class ZMappedCacheEntry { @@ -575,7 +576,7 @@ void ZMappedCache::print_on(outputStream* st) const { // class lists. const size_t entry_count = Atomic::load(&_entry_count); - st->print("Cache"); + st->print("Cache "); st->fill_to(17); st->print_cr("%zuM (%zu)", _size / M, entry_count); @@ -591,9 +592,9 @@ void ZMappedCache::print_on(outputStream* st) const { } // Print information on size classes - streamIndentor indentor(st, 1); + StreamAutoIndentor indentor(st, 1); - st->print("size classes"); + st->print("size classes "); st->fill_to(17); // Print the number of entries smaller than the min size class's size diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index 7bb1dcdcf81..ef4ea76f22f 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -1155,12 +1155,12 @@ void ZPartition::threads_do(ThreadClosure* tc) const { } void ZPartition::print_on(outputStream* st) const { - st->print("Partition %u", _numa_id); + st->print("Partition %u ", _numa_id); st->fill_to(17); st->print_cr("used %zuM, capacity %zuM, max capacity %zuM", _used / M, _capacity / M, _max_capacity / M); - streamIndentor indentor(st, 1); + StreamAutoIndentor indentor(st, 1); print_cache_on(st); } @@ -1168,11 +1168,10 @@ void ZPartition::print_cache_on(outputStream* st) const { _cache.print_on(st); } -void ZPartition::print_extended_on_error(outputStream* st) const { +void ZPartition::print_cache_extended_on(outputStream* st) const { st->print_cr("Partition %u", _numa_id); - streamIndentor indentor(st, 1); - + StreamAutoIndentor indentor(st, 1); _cache.print_extended_on(st); } @@ -2394,11 +2393,6 @@ void ZPageAllocator::threads_do(ThreadClosure* tc) const { } } -void ZPageAllocator::print_on(outputStream* st) const { - ZLocker lock(&_lock); - print_on_inner(st); -} - static bool try_lock_on_error(ZLock* lock) { if (VMError::is_error_reported() && VMError::is_error_reported_in_current_thread()) { return lock->try_lock(); @@ -2409,64 +2403,67 @@ static bool try_lock_on_error(ZLock* lock) { return true; } -void ZPageAllocator::print_extended_on_error(outputStream* st) const { - st->print_cr("ZMappedCache:"); - - streamIndentor indentor(st, 1); - - if (!try_lock_on_error(&_lock)) { - // We can't print without taking the lock since printing the contents of - // the cache requires iterating over the nodes in the cache's tree, which - // is not thread-safe. - st->print_cr(""); - - return; - } - - // Print each partition's cache content - ZPartitionConstIterator iter = partition_iterator(); - for (const ZPartition* partition; iter.next(&partition);) { - partition->print_extended_on_error(st); - } - - _lock.unlock(); -} - -void ZPageAllocator::print_on_error(outputStream* st) const { +void ZPageAllocator::print_usage_on(outputStream* st) const { const bool locked = try_lock_on_error(&_lock); if (!locked) { st->print_cr(""); } - // Print information even though we have not successfully taken the lock. + // Print information even though we may not have successfully taken the lock. // This is thread-safe, but may produce inconsistent results. - print_on_inner(st); + + print_total_usage_on(st); + + StreamAutoIndentor indentor(st, 1); + print_partition_usage_on(st); if (locked) { _lock.unlock(); } } -void ZPageAllocator::print_on_inner(outputStream* st) const { - // Print total usage - st->print("ZHeap"); +void ZPageAllocator::print_total_usage_on(outputStream* st) const { + st->print("ZHeap "); st->fill_to(17); st->print_cr("used %zuM, capacity %zuM, max capacity %zuM", used() / M, capacity() / M, max_capacity() / M); +} - // Print per-partition - - streamIndentor indentor(st, 1); - +void ZPageAllocator::print_partition_usage_on(outputStream* st) const { if (_partitions.count() == 1) { - // The summary printing is redundant if we only have one partition + // Partition usage is redundant if we only have one partition. Only + // print the cache. _partitions.get(0).print_cache_on(st); return; } + // Print all partitions ZPartitionConstIterator iter = partition_iterator(); for (const ZPartition* partition; iter.next(&partition);) { partition->print_on(st); } } + +void ZPageAllocator::print_cache_extended_on(outputStream* st) const { + st->print_cr("ZMappedCache:"); + + StreamAutoIndentor indentor(st, 1); + + if (!try_lock_on_error(&_lock)) { + // We can't print without taking the lock since printing the contents of + // the cache requires iterating over the nodes in the cache's tree, which + // is not thread-safe. + st->print_cr(""); + + return; + } + + // Print each partition's cache content + ZPartitionConstIterator iter = partition_iterator(); + for (const ZPartition* partition; iter.next(&partition);) { + partition->print_cache_extended_on(st); + } + + _lock.unlock(); +} diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index 5cd08aee94c..ba83686a87d 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -140,7 +140,7 @@ class ZPartition { void print_on(outputStream* st) const; void print_cache_on(outputStream* st) const; - void print_extended_on_error(outputStream* st) const; + void print_cache_extended_on(outputStream* st) const; }; using ZPartitionIterator = ZPerNUMAIterator; @@ -238,8 +238,6 @@ class ZPageAllocator { void update_collection_stats(ZGenerationId id); ZPageAllocatorStats stats_inner(ZGeneration* generation) const; - void print_on_inner(outputStream* st) const; - public: ZPageAllocator(size_t min_capacity, size_t initial_capacity, @@ -285,9 +283,10 @@ class ZPageAllocator { void threads_do(ThreadClosure* tc) const; - void print_on(outputStream* st) const; - void print_extended_on_error(outputStream* st) const; - void print_on_error(outputStream* st) const; + void print_usage_on(outputStream* st) const; + void print_total_usage_on(outputStream* st) const; + void print_partition_usage_on(outputStream* st) const; + void print_cache_extended_on(outputStream* st) const; }; class ZPageAllocatorStats { diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 04e5d807f32..ab7202d046a 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -63,6 +63,7 @@ #include "utilities/debug.hpp" #include "utilities/formatBuffer.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" using metaspace::ChunkManager; using metaspace::CommitLimiter; @@ -214,10 +215,11 @@ void MetaspaceUtils::print_report(outputStream* out, size_t scale) { void MetaspaceUtils::print_on(outputStream* out) { - // Used from all GCs. It first prints out totals, then, separately, the class space portion. + // First prints out totals, then, separately, the class space portion. MetaspaceCombinedStats stats = get_combined_statistics(); - out->print_cr(" Metaspace " - "used %zuK, " + out->print("Metaspace "); + out->fill_to(17); + out->print_cr("used %zuK, " "committed %zuK, " "reserved %zuK", stats.used()/K, @@ -225,8 +227,10 @@ void MetaspaceUtils::print_on(outputStream* out) { stats.reserved()/K); if (Metaspace::using_class_space()) { - out->print_cr(" class space " - "used %zuK, " + StreamAutoIndentor indentor(out, 1); + out->print("class space "); + out->fill_to(17); + out->print_cr("used %zuK, " "committed %zuK, " "reserved %zuK", stats.class_space_stats().used()/K, diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 6f415ab93a4..e846eb3ddde 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -1159,7 +1159,10 @@ void Universe::compute_base_vtable_size() { void Universe::print_on(outputStream* st) { GCMutexLocker hl(Heap_lock); // Heap_lock might be locked by caller thread. st->print_cr("Heap"); - heap()->print_on(st); + + StreamAutoIndentor indentor(st, 1); + heap()->print_heap_on(st); + MetaspaceUtils::print_on(st); } void Universe::print_heap_at_SIGBREAK() { diff --git a/src/hotspot/share/memory/virtualspace.cpp b/src/hotspot/share/memory/virtualspace.cpp index 2ea90a6c9dd..fa1de208804 100644 --- a/src/hotspot/share/memory/virtualspace.cpp +++ b/src/hotspot/share/memory/virtualspace.cpp @@ -422,13 +422,13 @@ void VirtualSpace::check_for_contiguity() { } void VirtualSpace::print_on(outputStream* out) const { - out->print ("Virtual space:"); - if (special()) out->print(" (pinned in memory)"); - out->cr(); - out->print_cr(" - committed: %zu", committed_size()); - out->print_cr(" - reserved: %zu", reserved_size()); - out->print_cr(" - [low, high]: [" PTR_FORMAT ", " PTR_FORMAT "]", p2i(low()), p2i(high())); - out->print_cr(" - [low_b, high_b]: [" PTR_FORMAT ", " PTR_FORMAT "]", p2i(low_boundary()), p2i(high_boundary())); + out->print_cr("Virtual space:%s", special() ? " (pinned in memory)" : ""); + + StreamAutoIndentor indentor(out, 1); + out->print_cr("- committed: %zu", committed_size()); + out->print_cr("- reserved: %zu", reserved_size()); + out->print_cr("- [low, high]: [" PTR_FORMAT ", " PTR_FORMAT "]", p2i(low()), p2i(high())); + out->print_cr("- [low_b, high_b]: [" PTR_FORMAT ", " PTR_FORMAT "]", p2i(low_boundary()), p2i(high_boundary())); } void VirtualSpace::print() const { @@ -436,3 +436,8 @@ void VirtualSpace::print() const { } #endif + +void VirtualSpace::print_space_boundaries_on(outputStream* out) const { + out->print_cr("[" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", + p2i(low_boundary()), p2i(high()), p2i(high_boundary())); +} diff --git a/src/hotspot/share/memory/virtualspace.hpp b/src/hotspot/share/memory/virtualspace.hpp index d5abf13b720..abc760ffeb3 100644 --- a/src/hotspot/share/memory/virtualspace.hpp +++ b/src/hotspot/share/memory/virtualspace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,6 +124,8 @@ class VirtualSpace { // Debugging void print_on(outputStream* out) const PRODUCT_RETURN; void print() const; + + void print_space_boundaries_on(outputStream* out) const; }; #endif // SHARE_MEMORY_VIRTUALSPACE_HPP diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index d257ef61be6..17906520f5c 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -37,6 +37,7 @@ #include "compiler/directivesParser.hpp" #include "gc/shared/gcVMOperations.hpp" #include "jvm.h" +#include "memory/metaspaceUtils.hpp" #include "memory/metaspace/metaspaceDCmd.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" @@ -411,7 +412,8 @@ void RunFinalizationDCmd::execute(DCmdSource source, TRAPS) { void HeapInfoDCmd::execute(DCmdSource source, TRAPS) { MutexLocker hl(THREAD, Heap_lock); - Universe::heap()->print_on(output()); + Universe::heap()->print_heap_on(output()); + MetaspaceUtils::print_on(output()); } void FinalizerInfoDCmd::execute(DCmdSource source, TRAPS) { diff --git a/src/hotspot/share/utilities/bitMap.cpp b/src/hotspot/share/utilities/bitMap.cpp index 03eb1620cf1..14b1dc8d10f 100644 --- a/src/hotspot/share/utilities/bitMap.cpp +++ b/src/hotspot/share/utilities/bitMap.cpp @@ -688,7 +688,7 @@ BitMap::idx_t BitMap::count_one_bits(idx_t beg, idx_t end) const { } -void BitMap::print_on_error(outputStream* st, const char* prefix) const { +void BitMap::print_range_on(outputStream* st, const char* prefix) const { st->print_cr("%s[" PTR_FORMAT ", " PTR_FORMAT ")", prefix, p2i(map()), p2i((char*)map() + (size() >> LogBitsPerByte))); } diff --git a/src/hotspot/share/utilities/bitMap.hpp b/src/hotspot/share/utilities/bitMap.hpp index 434993d45b9..af547eb539a 100644 --- a/src/hotspot/share/utilities/bitMap.hpp +++ b/src/hotspot/share/utilities/bitMap.hpp @@ -393,7 +393,7 @@ class BitMap { void write_to(bm_word_t* buffer, size_t buffer_size_in_bytes) const; // Printing - void print_on_error(outputStream* st, const char* prefix) const; + void print_range_on(outputStream* st, const char* prefix) const; void print_on(outputStream* st) const; }; diff --git a/src/hotspot/share/utilities/ostream.hpp b/src/hotspot/share/utilities/ostream.hpp index 46bd0b673c1..0a99ee886ad 100644 --- a/src/hotspot/share/utilities/ostream.hpp +++ b/src/hotspot/share/utilities/ostream.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -176,6 +176,7 @@ class outputStream : public CHeapObjBase { extern outputStream* tty; // tty output class streamIndentor : public StackObj { +protected: outputStream* const _str; const int _amount; NONCOPYABLE(streamIndentor); @@ -186,14 +187,13 @@ class streamIndentor : public StackObj { ~streamIndentor() { _str->dec(_amount); } }; -class StreamAutoIndentor : public StackObj { - outputStream* const _os; +class StreamAutoIndentor : public streamIndentor { const bool _old; NONCOPYABLE(StreamAutoIndentor); public: - StreamAutoIndentor(outputStream* os) : - _os(os), _old(os->set_autoindent(true)) {} - ~StreamAutoIndentor() { _os->set_autoindent(_old); } + StreamAutoIndentor(outputStream* os, int indentation = 0) : + streamIndentor(os, indentation), _old(os->set_autoindent(true)) {} + ~StreamAutoIndentor() { _str->set_autoindent(_old); } }; // advisory locking for the shared tty stream: diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index e1940123d67..ee402b8b894 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1200,7 +1200,15 @@ void VMError::report(outputStream* st, bool _verbose) { if (Universe::heap() != nullptr) { st->print_cr("Heap:"); - Universe::heap()->print_on_error(st); + StreamAutoIndentor indentor(st, 1); + Universe::heap()->print_heap_on(st); + MetaspaceUtils::print_on(st); + st->cr(); + } + + STEP_IF("printing GC information", _verbose) + if (Universe::heap() != nullptr) { + Universe::heap()->print_gc_on(st); st->cr(); } @@ -1382,16 +1390,32 @@ void VMError::print_vm_info(outputStream* st) { } #endif - // STEP("printing heap information") + // Take heap lock over both heap and GC printing so that information is + // consistent. + { + MutexLocker ml(Heap_lock); - if (Universe::is_fully_initialized()) { - MutexLocker hl(Heap_lock); - GCLogPrecious::print_on_error(st); - st->print_cr("Heap:"); - Universe::heap()->print_on_error(st); - st->cr(); - st->print_cr("Polling page: " PTR_FORMAT, p2i(SafepointMechanism::get_polling_page())); - st->cr(); + // STEP("printing heap information") + + if (Universe::is_fully_initialized()) { + GCLogPrecious::print_on_error(st); + + st->print_cr("Heap:"); + StreamAutoIndentor indentor(st, 1); + Universe::heap()->print_heap_on(st); + MetaspaceUtils::print_on(st); + st->cr(); + } + + // STEP("printing GC information") + + if (Universe::is_fully_initialized()) { + Universe::heap()->print_gc_on(st); + st->cr(); + + st->print_cr("Polling page: " PTR_FORMAT, p2i(SafepointMechanism::get_polling_page())); + st->cr(); + } } // STEP("printing metaspace information") From 356c4d9ca93c8a37231e86d583ce9628d693c733 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Thu, 24 Apr 2025 14:14:24 +0000 Subject: [PATCH 011/118] 8355369: Remove setAccessible usage for setting final fields in java.util.concurrent Reviewed-by: pminborg, dl, rgiulietti, alanb --- .../concurrent/ConcurrentSkipListSet.java | 19 +++++++++++-------- .../util/concurrent/CopyOnWriteArrayList.java | 15 +++++++-------- .../atomic/AtomicReferenceArray.java | 17 ++++++++--------- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java index 649eaa563c7..0b0db4e8120 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java @@ -35,7 +35,9 @@ package java.util.concurrent; -import java.lang.reflect.Field; +import jdk.internal.misc.Unsafe; + +import java.lang.invoke.VarHandle; import java.util.AbstractSet; import java.util.Collection; import java.util.Collections; @@ -176,6 +178,8 @@ public ConcurrentSkipListSet clone() { ConcurrentSkipListSet clone = (ConcurrentSkipListSet) super.clone(); clone.setMap(new ConcurrentSkipListMap(m)); + // Needed to ensure safe publication of setMap() + VarHandle.releaseFence(); return clone; } catch (CloneNotSupportedException e) { throw new InternalError(); @@ -527,12 +531,11 @@ public Spliterator spliterator() { /** Initializes map field; for use in clone. */ private void setMap(ConcurrentNavigableMap map) { - try { - Field mapField = ConcurrentSkipListSet.class.getDeclaredField("m"); - mapField.setAccessible(true); - mapField.set(this, map); - } catch (IllegalAccessException | NoSuchFieldException e) { - throw new Error(e); - } + final Unsafe U = Unsafe.getUnsafe(); + U.putReference( + this, + U.objectFieldOffset(ConcurrentSkipListSet.class, "m"), + map + ); } } diff --git a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java index 2d3bdb429e9..9024fca8024 100644 --- a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java +++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java @@ -35,7 +35,6 @@ package java.util.concurrent; import java.lang.invoke.VarHandle; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -57,6 +56,7 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.Unsafe; import jdk.internal.util.ArraysSupport; /** @@ -2095,12 +2095,11 @@ public List reversed() { /** Initializes the lock; for use when deserializing or cloning. */ private void resetLock() { - try { - Field lockField = CopyOnWriteArrayList.class.getDeclaredField("lock"); - lockField.setAccessible(true); - lockField.set(this, new Object()); - } catch (IllegalAccessException | NoSuchFieldException e) { - throw new Error(e); - } + final Unsafe U = Unsafe.getUnsafe(); + U.putReference( + this, + U.objectFieldOffset(CopyOnWriteArrayList.class, "lock"), + new Object() + ); } } diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java index ff4e9fa7355..67315296a8d 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java @@ -35,10 +35,11 @@ package java.util.concurrent.atomic; +import jdk.internal.misc.Unsafe; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.lang.reflect.Array; -import java.lang.reflect.Field; import java.util.Arrays; import java.util.function.BinaryOperator; import java.util.function.UnaryOperator; @@ -330,14 +331,13 @@ private void readObject(java.io.ObjectInputStream s) throw new java.io.InvalidObjectException("Not array type"); if (a.getClass() != Object[].class) a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class); - try { - Field arrayField = AtomicReferenceArray.class.getDeclaredField("array"); - arrayField.setAccessible(true); - arrayField.set(this, a); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new Error(e); - } + final Unsafe U = Unsafe.getUnsafe(); + U.putReference( + this, + U.objectFieldOffset(AtomicReferenceArray.class, "array"), + a + ); } // jdk9 @@ -523,5 +523,4 @@ public final boolean weakCompareAndSetAcquire(int i, E expectedValue, E newValue public final boolean weakCompareAndSetRelease(int i, E expectedValue, E newValue) { return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue); } - } From 0edd018a48c202a6da4afe80e245799b47000885 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 24 Apr 2025 14:48:00 +0000 Subject: [PATCH 012/118] 8355432: Remove CompileTask from SA Reviewed-by: cjplummer, lmesnik --- .../sun/jvm/hotspot/compiler/CompileTask.java | 73 ------------------- 1 file changed, 73 deletions(-) delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/CompileTask.java diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/CompileTask.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/CompileTask.java deleted file mode 100644 index e54facaeb72..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/compiler/CompileTask.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package sun.jvm.hotspot.compiler; - -import java.io.PrintStream; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.prims.JvmtiExport; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public class CompileTask extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("CompileTask"); - methodField = type.getAddressField("_method"); - osrBciField = new CIntField(type.getCIntegerField("_osr_bci"), 0); - compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0); - } - - private static AddressField methodField; - private static CIntField osrBciField; - private static CIntField compLevelField; - - public CompileTask(Address addr) { - super(addr); - } - - public Method method() { - Address oh = methodField.getValue(getAddress()); - return (Method)Metadata.instantiateWrapperFor(oh); - } - - public int osrBci() { - return (int)osrBciField.getValue(getAddress()); - } - - public int compLevel() { - return (int)compLevelField.getValue(getAddress()); - } -} From 751e0392bcad0e608a7a041b658c1d263383f15a Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Thu, 24 Apr 2025 15:55:05 +0000 Subject: [PATCH 013/118] 8355235: Clean out old versions from Tools.gmk Reviewed-by: erikj --- make/devkit/Tools.gmk | 134 +++++++++--------------------------------- 1 file changed, 27 insertions(+), 107 deletions(-) diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index f4323f58638..1b9240df49c 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -39,6 +39,8 @@ # Fix this... # +uppercase = $(shell echo $1 | tr a-z A-Z) + $(info TARGET=$(TARGET)) $(info HOST=$(HOST)) $(info BUILD=$(BUILD)) @@ -91,99 +93,28 @@ endif ################################################################################ # Define external dependencies -# Latest that could be made to work. -GCC_VER := 14.2.0 -ifeq ($(GCC_VER), 14.2.0) - gcc_ver := gcc-14.2.0 - binutils_ver := binutils-2.43 - ccache_ver := ccache-4.10.2 - CCACHE_CMAKE_BASED := 1 - mpfr_ver := mpfr-4.2.1 - gmp_ver := gmp-6.3.0 - mpc_ver := mpc-1.3.1 - gdb_ver := gdb-15.2 - REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 -else ifeq ($(GCC_VER), 13.2.0) - gcc_ver := gcc-13.2.0 - binutils_ver := binutils-2.41 - ccache_ver := ccache-3.7.12 - mpfr_ver := mpfr-4.2.0 - gmp_ver := gmp-6.3.0 - mpc_ver := mpc-1.3.1 - gdb_ver := gdb-13.2 - REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 -else ifeq ($(GCC_VER), 11.3.0) - gcc_ver := gcc-11.3.0 - binutils_ver := binutils-2.39 - ccache_ver := ccache-3.7.12 - mpfr_ver := mpfr-4.1.1 - gmp_ver := gmp-6.2.1 - mpc_ver := mpc-1.2.1 - gdb_ver := gdb-11.2 - REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 -else ifeq ($(GCC_VER), 11.2.0) - gcc_ver := gcc-11.2.0 - binutils_ver := binutils-2.37 - ccache_ver := ccache-3.7.12 - mpfr_ver := mpfr-4.1.0 - gmp_ver := gmp-6.2.1 - mpc_ver := mpc-1.2.1 - gdb_ver := gdb-11.1 - REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 -else ifeq ($(GCC_VER), 10.3.0) - gcc_ver := gcc-10.3.0 - binutils_ver := binutils-2.36.1 - ccache_ver := ccache-3.7.11 - mpfr_ver := mpfr-4.1.0 - gmp_ver := gmp-6.2.0 - mpc_ver := mpc-1.1.0 - gdb_ver := gdb-10.1 - REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 -else ifeq ($(GCC_VER), 10.2.0) - gcc_ver := gcc-10.2.0 - binutils_ver := binutils-2.35 - ccache_ver := ccache-3.7.11 - mpfr_ver := mpfr-4.1.0 - gmp_ver := gmp-6.2.0 - mpc_ver := mpc-1.1.0 - gdb_ver := gdb-9.2 - REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 -else ifeq ($(GCC_VER), 9.2.0) - gcc_ver := gcc-9.2.0 - binutils_ver := binutils-2.34 - ccache_ver := ccache-3.7.3 - mpfr_ver := mpfr-3.1.5 - gmp_ver := gmp-6.1.2 - mpc_ver := mpc-1.0.3 - gdb_ver := gdb-8.3 -else ifeq ($(GCC_VER), 8.3.0) - gcc_ver := gcc-8.3.0 - binutils_ver := binutils-2.32 - ccache_ver := ccache-3.7.3 - mpfr_ver := mpfr-3.1.5 - gmp_ver := gmp-6.1.2 - mpc_ver := mpc-1.0.3 - gdb_ver := gdb-8.3 -else ifeq ($(GCC_VER), 7.3.0) - gcc_ver := gcc-7.3.0 - binutils_ver := binutils-2.30 - ccache_ver := ccache-3.3.6 - mpfr_ver := mpfr-3.1.5 - gmp_ver := gmp-6.1.2 - mpc_ver := mpc-1.0.3 - gdb_ver := gdb-8.1 -else ifeq ($(GCC_VER), 4.9.2) - gcc_ver := gcc-4.9.2 - binutils_ver := binutils-2.25 - ccache_ver := ccache-3.2.1 - mpfr_ver := mpfr-3.0.1 - gmp_ver := gmp-4.3.2 - mpc_ver := mpc-1.0.1 - gdb_ver := gdb-7.12.1 -else - $(error Unsupported GCC version) -endif +gcc_ver_only := 14.2.0 +binutils_ver_only := 2.43 +ccache_ver_only := 4.10.2 +CCACHE_CMAKE_BASED := 1 +mpfr_ver_only := 4.2.1 +gmp_ver_only := 6.3.0 +mpc_ver_only := 1.3.1 +gdb_ver_only := 15.2 + +dependencies := gcc binutils ccache mpfr gmp mpc gdb +$(foreach dep,$(dependencies),$(eval $(dep)_ver := $(dep)-$($(dep)_ver_only))) + +GCC := http://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz +BINUTILS := http://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.gz +CCACHE := https://github.com/ccache/ccache/releases/download/v$(ccache_ver_only)/$(ccache_ver).tar.xz +MPFR := https://www.mpfr.org/$(mpfr_ver)/$(mpfr_ver).tar.bz2 +GMP := http://ftp.gnu.org/pub/gnu/gmp/$(gmp_ver).tar.bz2 +MPC := http://ftp.gnu.org/pub/gnu/mpc/$(mpc_ver).tar.gz +GDB := http://ftp.gnu.org/gnu/gdb/$(gdb_ver).tar.xz + +REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 ifneq ($(REQUIRED_MIN_MAKE_MAJOR_VERSION),) MAKE_MAJOR_VERSION := $(word 1,$(subst ., ,$(MAKE_VERSION))) SUPPORTED_MAKE_VERSION := $(shell [ $(MAKE_MAJOR_VERSION) -ge $(REQUIRED_MIN_MAKE_MAJOR_VERSION) ] && echo true) @@ -192,17 +123,6 @@ ifneq ($(REQUIRED_MIN_MAKE_MAJOR_VERSION),) endif endif -ccache_ver_only := $(patsubst ccache-%,%,$(ccache_ver)) - - -GCC := http://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz -BINUTILS := http://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.gz -CCACHE := https://github.com/ccache/ccache/releases/download/v$(ccache_ver_only)/$(ccache_ver).tar.xz -MPFR := https://www.mpfr.org/${mpfr_ver}/${mpfr_ver}.tar.bz2 -GMP := http://ftp.gnu.org/pub/gnu/gmp/${gmp_ver}.tar.bz2 -MPC := http://ftp.gnu.org/pub/gnu/mpc/${mpc_ver}.tar.gz -GDB := http://ftp.gnu.org/gnu/gdb/${gdb_ver}.tar.xz - # RPMs used by all BASE_OS RPM_LIST := \ $(KERNEL_HEADERS_RPM) \ @@ -297,7 +217,7 @@ define Download endef # Download and unpack all source packages -$(foreach p,GCC BINUTILS CCACHE MPFR GMP MPC GDB,$(eval $(call Download,$(p)))) +$(foreach dep,$(dependencies),$(eval $(call Download,$(call uppercase,$(dep))))) ################################################################################ # Unpack RPMS @@ -374,7 +294,7 @@ endif ################################################################################ # Define marker files for each source package to be compiled -$(foreach t,binutils mpfr gmp mpc gcc ccache gdb,$(eval $(t) = $(TARGETDIR)/$($(t)_ver).done)) +$(foreach dep,$(dependencies),$(eval $(dep) = $(TARGETDIR)/$($(dep)_ver).done)) ################################################################################ @@ -721,12 +641,12 @@ ifeq ($(TARGET), $(HOST)) ln -s $(TARGET)-$* $@ missing-links := $(addprefix $(PREFIX)/bin/, \ - addr2line ar as c++ c++filt dwp elfedit g++ gcc gcc-$(GCC_VER) gprof ld ld.bfd \ + addr2line ar as c++ c++filt dwp elfedit g++ gcc gcc-$(gcc_ver_only) gprof ld ld.bfd \ ld.gold nm objcopy objdump ranlib readelf size strings strip) endif # Add link to work around "plugin needed to handle lto object" (JDK-8344272) -$(PREFIX)/lib/bfd-plugins/liblto_plugin.so: $(PREFIX)/libexec/gcc/$(TARGET)/$(GCC_VER)/liblto_plugin.so +$(PREFIX)/lib/bfd-plugins/liblto_plugin.so: $(PREFIX)/libexec/gcc/$(TARGET)/$(gcc_ver_only)/liblto_plugin.so @echo 'Creating missing $(@F) soft link' @mkdir -p $(@D) ln -s $$(realpath -s --relative-to=$(@D) $<) $@ From 8e51ff70d896aeb5b35e6bb6b00f1818d67c99e7 Mon Sep 17 00:00:00 2001 From: Gennadiy Krivoshein Date: Thu, 24 Apr 2025 16:06:29 +0000 Subject: [PATCH 014/118] 8315113: Print request Chromaticity.MONOCHROME attribute does not work on macOS Reviewed-by: prr, psadhukhan --- .../classes/sun/lwawt/macosx/CPrinterJob.java | 13 +- .../sun/print/GrayscaleProxyGraphics2D.java | 211 ++++++++++++++ .../classes/sun/print/IPPPrintService.java | 13 +- .../print/attribute/MonochromePrintTest.java | 272 ++++++++++++++++++ 4 files changed, 505 insertions(+), 4 deletions(-) create mode 100644 src/java.desktop/share/classes/sun/print/GrayscaleProxyGraphics2D.java create mode 100644 test/jdk/javax/print/attribute/MonochromePrintTest.java diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index cb7333c79d6..1ca94eb3f51 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import javax.print.*; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.standard.Chromaticity; import javax.print.attribute.standard.Copies; import javax.print.attribute.standard.Destination; import javax.print.attribute.standard.Media; @@ -73,6 +74,8 @@ public final class CPrinterJob extends RasterPrinterJob { private Throwable printerAbortExcpn; + private boolean monochrome = false; + // This is the NSPrintInfo for this PrinterJob. Protect multi thread // access to it. It is used by the pageDialog, jobDialog, and printLoop. // This way the state of these items is shared across these calls. @@ -212,6 +215,11 @@ protected void setAttributes(PrintRequestAttributeSet attributes) throws Printer setPageRange(-1, -1); } } + + PrintService service = getPrintService(); + Chromaticity chromaticity = (Chromaticity)attributes.get(Chromaticity.class); + monochrome = chromaticity == Chromaticity.MONOCHROME && service != null && + service.isAttributeCategorySupported(Chromaticity.class); } private void setPageRangeAttribute(int from, int to, boolean isRangeSet) { @@ -788,6 +796,9 @@ private void printToPathGraphics( final PeekGraphics graphics, // Always an a Graphics2D pathGraphics = new CPrinterGraphics(delegate, printerJob); // Just stores delegate into an ivar Rectangle2D pageFormatArea = getPageFormatArea(page); initPrinterGraphics(pathGraphics, pageFormatArea); + if (monochrome) { + pathGraphics = new GrayscaleProxyGraphics2D(pathGraphics, printerJob); + } painter.print(pathGraphics, FlipPageFormat.getOriginal(page), pageIndex); delegate.dispose(); delegate = null; diff --git a/src/java.desktop/share/classes/sun/print/GrayscaleProxyGraphics2D.java b/src/java.desktop/share/classes/sun/print/GrayscaleProxyGraphics2D.java new file mode 100644 index 00000000000..25f32181b71 --- /dev/null +++ b/src/java.desktop/share/classes/sun/print/GrayscaleProxyGraphics2D.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, BELLSOFT. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.print; + + +import java.awt.Color; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.LinearGradientPaint; +import java.awt.Paint; +import java.awt.RadialGradientPaint; +import java.awt.TexturePaint; +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.print.PrinterJob; + +/** + * Proxy class to print with grayscale. + * Convert Colors, Paints and Images to the grayscale. + * + */ +public class GrayscaleProxyGraphics2D extends ProxyGraphics2D { + + /** + * The new ProxyGraphics2D will forward all graphics + * calls to 'graphics'. + * + * @param graphics + * @param printerJob + */ + public GrayscaleProxyGraphics2D(Graphics2D graphics, PrinterJob printerJob) { + super(graphics, printerJob); + } + + @Override + public void setBackground(Color color) { + Color gcolor = getGrayscaleColor(color); + super.setBackground(gcolor); + } + + @Override + public void setColor(Color c) { + Color gcolor = getGrayscaleColor(c); + super.setColor(gcolor); + } + + @Override + public void setPaint(Paint paint) { + if (paint instanceof Color color) { + super.setPaint(getGrayscaleColor(color)); + } else if (paint instanceof TexturePaint texturePaint) { + super.setPaint(new TexturePaint(getGrayscaleImage(texturePaint.getImage()), texturePaint.getAnchorRect())); + } else if (paint instanceof GradientPaint gradientPaint) { + super.setPaint(new GradientPaint(gradientPaint.getPoint1(), + getGrayscaleColor(gradientPaint.getColor1()), + gradientPaint.getPoint2(), + getGrayscaleColor(gradientPaint.getColor2()), + gradientPaint.isCyclic())); + } else if (paint instanceof LinearGradientPaint linearGradientPaint) { + Color[] colors = new Color[linearGradientPaint.getColors().length]; + Color[] oldColors = linearGradientPaint.getColors(); + for (int i = 0; i < colors.length; i++) { + colors[i] = getGrayscaleColor(oldColors[i]); + } + super.setPaint(new LinearGradientPaint(linearGradientPaint.getStartPoint(), + linearGradientPaint.getEndPoint(), + linearGradientPaint.getFractions(), + colors, + linearGradientPaint.getCycleMethod(), + linearGradientPaint.getColorSpace(), + linearGradientPaint.getTransform() + )); + } else if (paint instanceof RadialGradientPaint radialGradientPaint) { + Color[] colors = new Color[radialGradientPaint.getColors().length]; + Color[] oldColors = radialGradientPaint.getColors(); + for (int i = 0; i < colors.length; i++) { + colors[i] = getGrayscaleColor(oldColors[i]); + } + super.setPaint(new RadialGradientPaint(radialGradientPaint.getCenterPoint(), + radialGradientPaint.getRadius(), + radialGradientPaint.getFocusPoint(), + radialGradientPaint.getFractions(), + colors, + radialGradientPaint.getCycleMethod(), + radialGradientPaint.getColorSpace(), + radialGradientPaint.getTransform())); + } else if (paint == null) { + super.setPaint(paint); + } else { + throw new IllegalArgumentException("Unsupported Paint"); + } + } + + @Override + public void drawRenderedImage(RenderedImage img, AffineTransform xform) { + BufferedImage grayImage = new BufferedImage(img.getWidth() + img.getTileWidth(), + img.getHeight() + img.getTileHeight(), BufferedImage.TYPE_BYTE_GRAY); + Graphics2D g2 = grayImage.createGraphics(); + g2.drawRenderedImage(img, new AffineTransform()); + g2.dispose(); + super.drawRenderedImage(getGrayscaleImage(grayImage), xform); + } + + @Override + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) { + return super.drawImage(getGrayscaleImage(img), dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer); + } + + @Override + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) { + return super.drawImage(getGrayscaleImage(img), dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); + } + + @Override + public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { + return super.drawImage(getGrayscaleImage(img), x, y, width, height, bgcolor, observer); + } + + @Override + public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { + return super.drawImage(getGrayscaleImage(img), x, y, bgcolor, observer); + } + + @Override + public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { + return super.drawImage(getGrayscaleImage(img), x, y, width, height, observer); + } + + @Override + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { + return super.drawImage(getGrayscaleImage(img), x, y, observer); + } + + @Override + public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { + super.drawImage(getGrayscaleImage(img), op, x, y); + } + + @Override + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { + return super.drawImage(getGrayscaleImage(img), xform, obs); + } + + /** + * Returns grayscale variant of the input Color + * @param color color to transform to grayscale + * @return grayscale color + */ + private Color getGrayscaleColor(Color color) { + if (color == null) { + return null; + } + float[] gcolor = color.getComponents(ColorSpace.getInstance(ColorSpace.CS_GRAY), null); + return switch (gcolor.length) { + case 1 -> new Color(gcolor[0], gcolor[0], gcolor[0]); + case 2 -> new Color(gcolor[0], gcolor[0], gcolor[0], gcolor[1]); + default -> throw new IllegalArgumentException("Unknown grayscale color. " + + "Expected 1 or 2 components, received " + gcolor.length + " components."); + }; + } + + /** + * Converts Image to a grayscale + * @param img colored image + * @return grayscale BufferedImage + */ + private BufferedImage getGrayscaleImage(Image img) { + if (img == null) { + return null; + } + BufferedImage grayImage = new BufferedImage(img.getWidth(null), img.getHeight(null), + BufferedImage.TYPE_BYTE_GRAY); + Graphics grayGraphics = grayImage.getGraphics(); + grayGraphics.drawImage(img, 0, 0, null); + grayGraphics.dispose(); + return grayImage; + } + +} diff --git a/src/java.desktop/unix/classes/sun/print/IPPPrintService.java b/src/java.desktop/unix/classes/sun/print/IPPPrintService.java index 53089401e33..96fcdef3a52 100644 --- a/src/java.desktop/unix/classes/sun/print/IPPPrintService.java +++ b/src/java.desktop/unix/classes/sun/print/IPPPrintService.java @@ -572,8 +572,15 @@ public DocPrintJob createPrintJob() { flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) || !isIPPSupportedImages(flavor.getMimeType())) { - Chromaticity[]arr = new Chromaticity[1]; - arr[0] = Chromaticity.COLOR; + Chromaticity[] arr; + if (PrintServiceLookupProvider.isMac()) { + arr = new Chromaticity[2]; + arr[0] = Chromaticity.COLOR; + arr[1] = Chromaticity.MONOCHROME; + } else { + arr = new Chromaticity[1]; + arr[0] = Chromaticity.COLOR; + } return (arr); } else { return null; @@ -1400,7 +1407,7 @@ public boolean isAttributeValueSupported(Attribute attr, flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) || flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) || !isIPPSupportedImages(flavor.getMimeType())) { - return attr == Chromaticity.COLOR; + return PrintServiceLookupProvider.isMac() || attr == Chromaticity.COLOR; } else { return false; } diff --git a/test/jdk/javax/print/attribute/MonochromePrintTest.java b/test/jdk/javax/print/attribute/MonochromePrintTest.java new file mode 100644 index 00000000000..841183f04bb --- /dev/null +++ b/test/jdk/javax/print/attribute/MonochromePrintTest.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, BELLSOFT. All rights reserved. + * 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.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.Size2DSyntax; +import javax.print.attribute.standard.Chromaticity; +import javax.print.attribute.standard.MediaSize; +import javax.print.attribute.standard.MediaSizeName; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListCellRenderer; +import javax.swing.border.EmptyBorder; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.LinearGradientPaint; +import java.awt.MultipleGradientPaint; +import java.awt.Paint; +import java.awt.RadialGradientPaint; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.util.ArrayList; +import java.util.List; + +/* + * @test + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @bug 8315113 + * @key printer + * @requires (os.family == "mac") + * @summary javax.print: Support monochrome printing + * @run main/manual MonochromePrintTest + */ + +public class MonochromePrintTest { + + private static final String INSTRUCTIONS = """ + This test checks availability of the monochrome printing + on color printers. + To be able to run this test it is required to have a color + printer configured in your user environment. + Test's steps: + - Choose a printer. + - Press 'Print' button. + Visual inspection of the printed pages is needed. + A passing test will print two pages with + color and grayscale appearances + """; + + public static void main(String[] args) throws Exception { + PrintService[] availablePrintServices = getTestablePrintServices(); + if (availablePrintServices.length == 0) { + System.out.println("Available print services not found"); + return; + } + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .testTimeOut(300) + .title("Monochrome printing") + .testUI(createTestWindow(availablePrintServices)) + .build() + .awaitAndCheck(); + } + + private static Window createTestWindow(final PrintService[] availablePrintServices) { + Window frame = new JFrame("Choose service to test"); + JPanel pnlMain = new JPanel(); + pnlMain.setBorder(new EmptyBorder(5,5,5,5)); + pnlMain.setLayout(new GridLayout(3, 1, 5, 5)); + JLabel lblServices = new JLabel("Available services"); + JComboBox cbServices = new JComboBox<>(); + JButton btnPrint = new JButton("Print"); + btnPrint.setEnabled(false); + cbServices.setRenderer(new ListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, PrintService value, + int index, boolean isSelected, boolean cellHasFocus) { + return new JLabel(value == null ? "" : value.getName()); + } + }); + cbServices.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + btnPrint.setEnabled(cbServices.getSelectedItem() != null); + } + }); + for (PrintService ps : availablePrintServices) { + cbServices.addItem(ps); + } + lblServices.setLabelFor(cbServices); + btnPrint.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + PrintService printService = (PrintService) cbServices.getSelectedItem(); + if (printService != null) { + cbServices.setEnabled(false); + btnPrint.setEnabled(false); + test(printService); + } + } + }); + pnlMain.add(lblServices); + pnlMain.add(cbServices); + pnlMain.add(btnPrint); + frame.add(pnlMain); + frame.pack(); + return frame; + } + + private static PrintService[] getTestablePrintServices() { + List testablePrintServices = new ArrayList<>(); + for (PrintService ps : PrintServiceLookup.lookupPrintServices(null,null)) { + if (ps.isAttributeValueSupported(Chromaticity.MONOCHROME, null, null) && + ps.isAttributeValueSupported(Chromaticity.COLOR, null, null)) { + testablePrintServices.add(ps); + } + } + return testablePrintServices.toArray(new PrintService[0]); + } + + private static void test(PrintService printService) { + try { + print(printService, Chromaticity.COLOR); + print(printService, Chromaticity.MONOCHROME); + } catch (PrinterException ex) { + throw new RuntimeException(ex); + } + } + + private static void print(PrintService printService, Chromaticity chromaticity) + throws PrinterException { + PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet(); + attr.add(chromaticity); + PrinterJob job = PrinterJob.getPrinterJob(); + job.setPrintService(printService); + job.setJobName("Print with " + chromaticity); + job.setPrintable(new ChromaticityAttributePrintable(chromaticity)); + job.print(attr); + } + + private static class ChromaticityAttributePrintable implements Printable { + + private final Chromaticity chromaticity; + + public ChromaticityAttributePrintable(Chromaticity chromaticity) { + this.chromaticity = chromaticity; + } + + @Override + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) { + + if (pageIndex != 0) { + return NO_SUCH_PAGE; + } + + final int sx = (int) Math.ceil(pageFormat.getImageableX()); + final int sy = (int) Math.ceil(pageFormat.getImageableY()); + + Graphics2D g = (Graphics2D) graphics; + + BufferedImage bufferdImage = getBufferedImage((int) Math.ceil(pageFormat.getImageableWidth() / 3), + (int) Math.ceil(pageFormat.getImageableHeight() / 7)); + g.drawImage(bufferdImage, null, sx, sy); + + double defaultMediaSizeWidth = MediaSize.getMediaSizeForName(MediaSizeName.ISO_A4) + .getX(Size2DSyntax.INCH) * 72; + double scale = pageFormat.getWidth() / defaultMediaSizeWidth; + + final int squareSideLenngth = (int)(50 * scale); + final int offset = (int)(10 * scale); + int imh = sy + (int) Math.ceil(pageFormat.getImageableHeight() / 7) + offset; + + g.setColor(Color.ORANGE); + g.drawRect(sx, imh, squareSideLenngth, squareSideLenngth); + imh = imh + squareSideLenngth + offset; + + g.setColor(Color.BLUE); + g.fillOval(sx, imh, squareSideLenngth, squareSideLenngth); + imh = imh + squareSideLenngth + offset; + + Paint paint = new LinearGradientPaint(0, 0, + squareSideLenngth>>1, offset>>1, new float[]{0.0f, 0.2f, 1.0f}, + new Color[]{Color.RED, Color.GREEN, Color.CYAN}, MultipleGradientPaint.CycleMethod.REPEAT); + g.setPaint(paint); + g.setStroke(new BasicStroke(squareSideLenngth)); + g.fillRect(sx, imh + offset, squareSideLenngth, squareSideLenngth); + imh = imh + squareSideLenngth + offset; + + paint = new RadialGradientPaint(offset, offset, offset>>1, new float[]{0.0f, 0.5f, 1.0f}, + new Color[]{Color.RED, Color.GREEN, Color.CYAN}, MultipleGradientPaint.CycleMethod.REPEAT); + g.setPaint(paint); + g.fillRect(sx, imh + offset, squareSideLenngth, squareSideLenngth); + imh = imh + squareSideLenngth + offset; + + g.setStroke(new BasicStroke(offset>>1)); + g.setColor(Color.PINK); + g.drawString("This page should be " + chromaticity, sx, imh + squareSideLenngth); + + return PAGE_EXISTS; + } + + private BufferedImage getBufferedImage(int width, int height) { + Color[] colors = new Color[]{ + Color.RED, Color.ORANGE, Color.BLUE, + Color.CYAN, Color.MAGENTA, Color.GREEN + }; + BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + final int secondSquareOffset = width / 3; + final int thirdSquareOffset = secondSquareOffset * 2; + final int squareHeight = height / 2; + + int offset = 0; + Color color; + for (int y = 0; y < height; y++) { + if (y > squareHeight) { + offset = 3; + } + for (int x = 0; x < width; x++) { + if (x >= thirdSquareOffset) { + color = colors[offset + 2]; + } else if (x >= secondSquareOffset) { + color = colors[offset + 1]; + } else { + color = colors[offset]; + } + bufferedImage.setRGB(x, y, color.getRGB()); + } + } + return bufferedImage; + } + } + +} \ No newline at end of file From 3270a7d3591eac44705ff5d76c6f59cfb14f5ac0 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Thu, 24 Apr 2025 16:21:44 +0000 Subject: [PATCH 015/118] 8355476: RISC-V: using zext_w directly in vector_update_crc32 could trigger assert Reviewed-by: fyang, fjiang --- 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 218da7cde03..825722ad29b 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1806,7 +1806,7 @@ void MacroAssembler::vector_update_crc32(Register crc, Register buf, Register le for (int i = 0; i < N; i++) { vmv_x_s(tmp2, vcrc); // in vmv_x_s, the value is sign-extended to SEW bits, but we need zero-extended here. - zext_w(tmp2, tmp2); + zext(tmp2, tmp2, 32); vslidedown_vi(vcrc, vcrc, 1); xorr(crc, crc, tmp2); for (int j = 0; j < W; j++) { From 862797f0c16ed0459cda4931824b6b17120a2abe Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Thu, 24 Apr 2025 16:23:12 +0000 Subject: [PATCH 016/118] 8355293: [TEST] RISC-V: enable more ir tests Reviewed-by: fyang, luhenry --- .../loopopts/superword/ProdRed_Double.java | 8 +++++++ .../loopopts/superword/ProdRed_Float.java | 4 ++++ .../loopopts/superword/ProdRed_Int.java | 3 +-- .../TestRangeCheckHoistingScaledIV.java | 3 ++- .../runner/ArrayShiftOpTest.java | 23 +++++++----------- .../vectorization/runner/BasicIntOpTest.java | 24 +++++++++---------- 6 files changed, 36 insertions(+), 29 deletions(-) diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java index ea6939aa694..41284c0d61e 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java @@ -88,6 +88,10 @@ public static void prodReductionInit(double[] a, double[] b) { @IR(applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, applyIfCPUFeature = {"sse2", "true"}, counts = {IRNode.MUL_REDUCTION_VD, ">= 1"}) + // There is no efficient way to implement strict-ordered version on riscv64. + @IR(applyIf = {"SuperWordReductions", "true"}, + applyIfCPUFeature = {"rvv", "true"}, + failOn = {IRNode.MUL_REDUCTION_VD}) public static double prodReductionImplement(double[] a, double[] b, double total) { for (int i = 0; i < a.length; i++) { total *= a[i] - b[i]; @@ -101,6 +105,10 @@ public static double prodReductionImplement(double[] a, double[] b, double total @IR(applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, applyIfCPUFeature = {"sse2", "true"}, counts = {IRNode.MUL_REDUCTION_VD, ">= 1"}) + // There is no efficient way to implement strict-ordered version on riscv64. + @IR(applyIf = {"SuperWordReductions", "true"}, + applyIfCPUFeature = {"rvv", "true"}, + failOn = {IRNode.MUL_REDUCTION_VD}) public static double prodReductionWithStoreImplement(double[] a, double[] b, double[] c, double total) { for (int i = 0; i < a.length; i++) { c[i] = a[i] - b[i]; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java index c18aad33fb1..603530f7fb2 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java @@ -86,6 +86,10 @@ public static void prodReductionInit(float[] a, float[] b) { @IR(applyIfCPUFeature = {"sse4.1", "true"}, applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, counts = {IRNode.MUL_REDUCTION_VF, ">= 1"}) + // There is no efficient way to implement strict-ordered version on riscv64. + @IR(applyIfCPUFeature = {"rvv", "true"}, + applyIf = {"SuperWordReductions", "true"}, + failOn = {IRNode.MUL_REDUCTION_VF}) public static float prodReductionImplement(float[] a, float[] b, float total) { for (int i = 0; i < a.length; i++) { total *= a[i] - b[i]; diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java index ebc8251e025..9ca670117cf 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java @@ -85,8 +85,7 @@ public static void prodReductionInit(int[] a, int[] b) { @IR(applyIfCPUFeature = {"sse4.1", "true"}, applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, counts = {IRNode.MUL_REDUCTION_VI, ">= 1", IRNode.MUL_REDUCTION_VI, "<= 2"}) // one for main-loop, one for vector-post-loop - @IR(applyIfPlatform = {"riscv64", "true"}, - applyIfCPUFeature = {"rvv", "true"}, + @IR(applyIfCPUFeature = {"rvv", "true"}, applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, counts = {IRNode.MUL_REDUCTION_VI, ">= 1", IRNode.MUL_REDUCTION_VI, "<= 2"}) // one for main-loop, one for vector-post-loop public static int prodReductionImplement(int[] a, int[] b, int total) { diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java index b9a3028978f..4b4026c452a 100644 --- a/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java +++ b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2023, Arm Limited. All rights reserved. + * Copyright (c) 2025, Rivos Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +28,7 @@ * @summary Test range check hoisting for some scaled iv at array index * @library /test/lib / * @requires vm.flagless - * @requires vm.debug & vm.compiler2.enabled & (os.simpleArch == "x64" | os.arch == "aarch64") + * @requires vm.debug & vm.compiler2.enabled & (os.simpleArch == "x64" | os.arch == "aarch64" | os.arch == "riscv64") * @modules jdk.incubator.vector * @run main/othervm compiler.rangechecks.TestRangeCheckHoistingScaledIV */ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java index ec1e3f998ca..bcf5196d694 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java @@ -1,6 +1,7 @@ /* * Copyright (c) 2022, 2023, Arm Limited. All rights reserved. * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Rivos Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,12 +76,9 @@ public ArrayShiftOpTest() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"}, counts = {IRNode.STORE_VECTOR, ">0"}) - @IR(applyIfCPUFeature = {"avx512f", "true"}, - counts = {IRNode.ROTATE_RIGHT_V, ">0"}) - @IR(applyIfPlatform = {"riscv64", "true"}, - applyIfCPUFeature = {"zvbb", "true"}, + @IR(applyIfCPUFeatureOr = {"avx512f", "true", "zvbb", "true"}, counts = {IRNode.ROTATE_RIGHT_V, ">0"}) public int[] intCombinedRotateShift() { int[] res = new int[SIZE]; @@ -91,9 +89,9 @@ public int[] intCombinedRotateShift() { } @Test - @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true"}, + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true", "rvv", "true"}, counts = {IRNode.STORE_VECTOR, ">0"}) - @IR(applyIfCPUFeature = {"avx512f", "true"}, + @IR(applyIfCPUFeatureOr = {"avx512f", "true", "zvbb", "true"}, counts = {IRNode.ROTATE_RIGHT_V, ">0"}) // Requires size to not be known at compile time, otherwise the shift // can get constant folded with the (iv + const) pattern from the @@ -107,12 +105,9 @@ public int[] intCombinedRotateShiftWithPopulateIndex() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"}, counts = {IRNode.STORE_VECTOR, ">0"}) - @IR(applyIfCPUFeature = {"avx512f", "true"}, - counts = {IRNode.ROTATE_RIGHT_V, ">0"}) - @IR(applyIfPlatform = {"riscv64", "true"}, - applyIfCPUFeature = {"zvbb", "true"}, + @IR(applyIfCPUFeatureOr = {"avx512f", "true", "zvbb", "true"}, counts = {IRNode.ROTATE_RIGHT_V, ">0"}) public long[] longCombinedRotateShift() { long[] res = new long[SIZE]; @@ -135,9 +130,9 @@ public long[] longExplicitRotateWithPopulateIndex() { } @Test - @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true"}, + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true", "rvv", "true"}, counts = {IRNode.STORE_VECTOR, ">0"}) - @IR(applyIfCPUFeature = {"avx512f", "true"}, + @IR(applyIfCPUFeatureOr = {"avx512f", "true", "zvbb", "true"}, counts = {IRNode.ROTATE_RIGHT_V, ">0"}) @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true"}, counts = {IRNode.POPULATE_INDEX, ">0"}) diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicIntOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicIntOpTest.java index 54f7f9a7261..9f1e5789056 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicIntOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicIntOpTest.java @@ -64,7 +64,7 @@ public BasicIntOpTest() { // ---------------- Arithmetic ---------------- @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true", "rvv", "true"}, counts = {IRNode.SUB_VI, ">0"}) public int[] vectorNeg() { int[] res = new int[SIZE]; @@ -75,7 +75,7 @@ public int[] vectorNeg() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "ssse3", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "ssse3", "true", "rvv", "true"}, counts = {IRNode.ABS_VI, ">0"}) public int[] vectorAbs() { int[] res = new int[SIZE]; @@ -86,7 +86,7 @@ public int[] vectorAbs() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true", "rvv", "true"}, counts = {IRNode.ADD_VI, ">0"}) public int[] vectorAdd() { int[] res = new int[SIZE]; @@ -97,7 +97,7 @@ public int[] vectorAdd() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true", "rvv", "true"}, counts = {IRNode.SUB_VI, ">0"}) public int[] vectorSub() { int[] res = new int[SIZE]; @@ -108,7 +108,7 @@ public int[] vectorSub() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse4.1", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse4.1", "true", "rvv", "true"}, counts = {IRNode.MUL_VI, ">0"}) public int[] vectorMul() { int[] res = new int[SIZE]; @@ -119,7 +119,7 @@ public int[] vectorMul() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse4.1", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse4.1", "true", "rvv", "true"}, counts = {IRNode.MUL_VI, ">0", IRNode.ADD_VI, ">0"}) public int[] vectorMulAdd() { int[] res = new int[SIZE]; @@ -130,7 +130,7 @@ public int[] vectorMulAdd() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse4.1", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse4.1", "true", "rvv", "true"}, counts = {IRNode.MUL_VI, ">0", IRNode.SUB_VI, ">0"}) public int[] vectorMulSub() { int[] res = new int[SIZE]; @@ -141,7 +141,7 @@ public int[] vectorMulSub() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"}, counts = {IRNode.POPCOUNT_VI, ">0"}) public int[] vectorPopCount() { int[] res = new int[SIZE]; @@ -153,7 +153,7 @@ public int[] vectorPopCount() { // ---------------- Logic ---------------- @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true", "rvv", "true"}, counts = {IRNode.XOR_VI, ">0"}) public int[] vectorNot() { int[] res = new int[SIZE]; @@ -164,7 +164,7 @@ public int[] vectorNot() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true", "rvv", "true"}, counts = {IRNode.AND_VI, ">0"}) public int[] vectorAnd() { int[] res = new int[SIZE]; @@ -175,7 +175,7 @@ public int[] vectorAnd() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true", "rvv", "true"}, counts = {IRNode.OR_VI, ">0"}) public int[] vectorOr() { int[] res = new int[SIZE]; @@ -186,7 +186,7 @@ public int[] vectorOr() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true", "rvv", "true"}, counts = {IRNode.XOR_VI, ">0"}) public int[] vectorXor() { int[] res = new int[SIZE]; From 29f10700e7c76d94db00e48b98a9c6dfedffac0d Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Thu, 24 Apr 2025 17:17:54 +0000 Subject: [PATCH 017/118] 8355211: nsk/jdi/EventRequest/disable/disable001.java should use JDIBase superclass Reviewed-by: lmesnik, amenkov --- .../jdi/EventRequest/disable/disable001.java | 163 +----------------- 1 file changed, 9 insertions(+), 154 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/disable/disable001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/disable/disable001.java index 92e8b14db91..75e9f40790c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/disable/disable001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequest/disable/disable001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,20 +76,7 @@ *
*/ -public class disable001 { - - //----------------------------------------------------- templete section - static final int PASSED = 0; - static final int FAILED = 2; - static final int PASS_BASE = 95; - - //----------------------------------------------------- templete parameters - static final String - sHeader1 = "\n==> nsk/jdi/EventRequest/disable/disable001 ", - sHeader2 = "--> debugger: ", - sHeader3 = "##> debugger: "; - - //----------------------------------------------------- main method +public class disable001 extends JDIBase { public static void main (String argv[]) { @@ -110,20 +97,6 @@ public static int run (String argv[], PrintStream out) { return exitCode; } - //-------------------------------------------------- log procedures - - private static Log logHandler; - - private static void log1(String message) { - logHandler.display(sHeader1 + message); - } - private static void log2(String message) { - logHandler.display(sHeader2 + message); - } - private static void log3(String message) { - logHandler.complain(sHeader3 + message); - } - // ************************************************ test parameters private String debuggeeName = @@ -132,28 +105,7 @@ private static void log3(String message) { private String testedClassName = "nsk.jdi.EventRequest.disable.disable001aTestClass11"; - Location location = null; // !!!!!!!!!!!!! see settingBreakpoint - //====================================================== test program - //------------------------------------------------------ common section - - static Debugee debuggee; - static ArgumentHandler argsHandler; - - static int waitTime; - - static VirtualMachine vm = null; - static EventRequestManager eventRManager = null; - static EventQueue eventQueue = null; - static EventSet eventSet = null; - static EventIterator eventIterator = null; - - static ReferenceType debuggeeClass = null; - - static int testExitCode = PASSED; - - - //------------------------------------------------------ methods private int runThis (String argv[], PrintStream out) { @@ -292,14 +244,12 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - BreakpointRequest bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); + BreakpointRequest bpRequest = + setupBreakpointForCommunication(debuggeeClass); + // setupBreakpointForCommunication() defaults to SUSPEND_EVENT_THREAD. We need + // to change this to SUSPEND_ALL. + bpRequest.disable(); + bpRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); bpRequest.enable(); //------------------------------------------------------ testing section @@ -405,7 +355,7 @@ private void testRun() case 11: log2(".....setting up BreakpointRequest"); - eventRequest1 = eventRManager.createBreakpointRequest(location); + eventRequest1 = eventRManager.createBreakpointRequest(breakpLocation); break; @@ -434,99 +384,4 @@ private void testRun() return; } - /* - * private BreakpointRequest settingBreakpoint(ThreadReference, ReferenceType, - * String, String, String) - * - * It sets up a breakpoint at given line number within a given method in a given class - * for a given thread. - * - * Return value: BreakpointRequest object in case of success - * - * JDITestRuntimeException in case of an Exception thrown within the method - */ - - private BreakpointRequest settingBreakpoint ( ThreadReference thread, - ReferenceType testedClass, - String methodName, - String bpLine, - String property) - throws JDITestRuntimeException { - - log2("......setting up a breakpoint:"); - log2(" thread: " + thread + "; class: " + testedClass + - "; method: " + methodName + "; line: " + bpLine); - - List alllineLocations = null; - Location lineLocation = null; - BreakpointRequest breakpRequest = null; - - try { - Method method = (Method) testedClass.methodsByName(methodName).get(0); - - alllineLocations = method.allLineLocations(); - - int n = - ( (IntegerValue) testedClass.getValue(testedClass.fieldByName(bpLine) ) ).value(); - if (n > alllineLocations.size()) { - log3("ERROR: TEST_ERROR_IN_settingBreakpoint(): number is out of bound of method's lines"); - } else { - lineLocation = (Location) alllineLocations.get(n); - -// this is only for this test to get Location object -location = lineLocation; - - try { - breakpRequest = eventRManager.createBreakpointRequest(lineLocation); - breakpRequest.putProperty("number", property); - breakpRequest.addThreadFilter(thread); - breakpRequest.setSuspendPolicy( EventRequest.SUSPEND_ALL); - } catch ( Exception e1 ) { - log3("ERROR: inner Exception within settingBreakpoint() : " + e1); - breakpRequest = null; - } - } - } catch ( Exception e2 ) { - log3("ERROR: ATTENTION: outer Exception within settingBreakpoint() : " + e2); - breakpRequest = null; - } - - if (breakpRequest == null) { - log2(" A BREAKPOINT HAS NOT BEEN SET UP"); - throw new JDITestRuntimeException("**FAILURE to set up a breakpoint**"); - } - - log2(" a breakpoint has been set up"); - return breakpRequest; - } - - - private void getEventSet() - throws JDITestRuntimeException { - try { -// log2(" eventSet = eventQueue.remove(waitTime);"); - eventSet = eventQueue.remove(waitTime); - if (eventSet == null) { - throw new JDITestRuntimeException("** TIMEOUT while waiting for event **"); - } -// log2(" eventIterator = eventSet.eventIterator;"); - eventIterator = eventSet.eventIterator(); - } catch ( Exception e ) { - throw new JDITestRuntimeException("** EXCEPTION while waiting for event ** : " + e); - } - } - - - private void breakpointForCommunication() - throws JDITestRuntimeException { - - log2("breakpointForCommunication"); - getEventSet(); - - if (eventIterator.nextEvent() instanceof BreakpointEvent) - return; - - throw new JDITestRuntimeException("** event IS NOT a breakpoint **"); - } - } From 370e6113de30fd1bc596b5fbf7bd00f97e689f4f Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Thu, 24 Apr 2025 17:19:15 +0000 Subject: [PATCH 018/118] 8355221: Get rid of unnecessary override of JDIBase.breakpointForCommunication in nsk/jdi tests Reviewed-by: lmesnik, amenkov --- .../addClassExclusionFilter/filter003.java | 26 +---------------- .../addClassFilter_rt/filter_rt002.java | 26 +---------------- .../addClassFilter_s/filter_s002.java | 25 +---------------- .../classPrepareRequests/clsprepreq002.java | 26 +---------------- .../methodExitRequests/methexitreq002.java | 26 +---------------- .../addClassExclusionFilter/filter002.java | 28 +------------------ .../addClassExclusionFilter/filter002.java | 26 +---------------- 7 files changed, 7 insertions(+), 176 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassExclusionFilter/filter003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassExclusionFilter/filter003.java index c0bfe91a750..b3c364a8dfe 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassExclusionFilter/filter003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassExclusionFilter/filter003.java @@ -311,7 +311,7 @@ private void testRun() vm.resume(); - breakpointForCommunication(); + breakpointForCommunication(debuggeeName); int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -327,30 +327,6 @@ private void testRun() return; } - protected void breakpointForCommunication() - throws JDITestRuntimeException { - log2("breakpointForCommunication"); - - do { - getEventSet(); - - Event event = eventIterator.nextEvent(); - if (event instanceof BreakpointEvent) - return; - - log2(" received: " + event); - - if (EventFilters.filtered(event, debuggeeName)) { - eventSet.resume(); - } - else { - break; - } - } while (true); - - throw new JDITestRuntimeException("** event IS NOT a breakpoint **"); - } - // ============================== test's additional methods private ClassPrepareRequest setting22ClassPrepareRequest ( String testedClass, diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_rt/filter_rt002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_rt/filter_rt002.java index 9be0d89a4b9..0ab2c332e22 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_rt/filter_rt002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_rt/filter_rt002.java @@ -264,7 +264,7 @@ private void testRun() for (int i = 0; ; i++) { vm.resume(); - breakpointForCommunication(); + breakpointForCommunication(debuggeeName); int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -334,30 +334,6 @@ private void testRun() return; } - protected void breakpointForCommunication() - throws JDITestRuntimeException { - log2("breakpointForCommunication"); - - do { - getEventSet(); - - Event event = eventIterator.nextEvent(); - if (event instanceof BreakpointEvent) - return; - - log2(" received: " + event); - - if (EventFilters.filtered(event, debuggeeName)) { - eventSet.resume(); - } - else { - break; - } - } while (true); - - throw new JDITestRuntimeException("** event IS NOT a breakpoint **"); - } - // ============================== test's additional methods private ClassPrepareRequest setting21ClassPrepareRequest ( ReferenceType testedClass, diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_s/filter_s002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_s/filter_s002.java index 1cc0dff5c99..20dd7839953 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_s/filter_s002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassPrepareRequest/addClassFilter_s/filter_s002.java @@ -267,7 +267,7 @@ private void testRun() for (int i = 0; ; i++) { vm.resume(); - breakpointForCommunication(); + breakpointForCommunication(debuggeeName); int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -332,29 +332,6 @@ private void testRun() log1(" TESTING ENDS"); return; } - protected void breakpointForCommunication() - throws JDITestRuntimeException { - log2("breakpointForCommunication"); - - do { - getEventSet(); - - Event event = eventIterator.nextEvent(); - if (event instanceof BreakpointEvent) - return; - - log2(" received: " + event); - - if (EventFilters.filtered(event, debuggeeName)) { - eventSet.resume(); - } - else { - break; - } - } while (true); - - throw new JDITestRuntimeException("** event IS NOT a breakpoint **"); - } // ============================== test's additional methods diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classPrepareRequests/clsprepreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classPrepareRequests/clsprepreq002.java index b2905b6527e..bbf36fbd319 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classPrepareRequests/clsprepreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/classPrepareRequests/clsprepreq002.java @@ -260,7 +260,7 @@ private void testRun() for (int i = 0; ; i++) { vm.resume(); - breakpointForCommunication(); + breakpointForCommunication(debuggeeName); int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -366,28 +366,4 @@ private void testRun() return; } - protected void breakpointForCommunication() - throws JDITestRuntimeException { - log2("breakpointForCommunication"); - - do { - getEventSet(); - - Event event = eventIterator.nextEvent(); - if (event instanceof BreakpointEvent) - return; - - log2(" received: " + event); - - if (EventFilters.filtered(event, debuggeeName)) { - eventSet.resume(); - } - else { - break; - } - } while (true); - - throw new JDITestRuntimeException("** event IS NOT a breakpoint **"); - } - } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodExitRequests/methexitreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodExitRequests/methexitreq002.java index f975441a9ba..a36534fc483 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodExitRequests/methexitreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodExitRequests/methexitreq002.java @@ -259,7 +259,7 @@ private void testRun() for (int i = 0; ; i++) { vm.resume(); - breakpointForCommunication(); + breakpointForCommunication(debuggeeName); int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -360,28 +360,4 @@ private void testRun() return; } - protected void breakpointForCommunication() - throws JDITestRuntimeException { - log2("breakpointForCommunication"); - - do { - getEventSet(); - - Event event = eventIterator.nextEvent(); - if (event instanceof BreakpointEvent) - return; - - log2(" received: " + event); - - if (EventFilters.filtered(event, debuggeeName)) { - eventSet.resume(); - } - else { - break; - } - } while (true); - - throw new JDITestRuntimeException("** event IS NOT a breakpoint **"); - } - } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassExclusionFilter/filter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassExclusionFilter/filter002.java index 6e293a98670..8996798d44c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassExclusionFilter/filter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodEntryRequest/addClassExclusionFilter/filter002.java @@ -263,7 +263,7 @@ private void testRun() for (int i = 0; ; i++) { vm.resume(); - breakpointForCommunication(); + breakpointForCommunication(debuggeeName); int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -331,32 +331,6 @@ private void testRun() return; } - protected void breakpointForCommunication() - throws JDITestRuntimeException { - log2("breakpointForCommunication"); - - do { - getEventSet(); - - Event event = eventIterator.nextEvent(); - if (event instanceof BreakpointEvent) - return; - - log2(" received: " + event); - - if (EventFilters.filtered(event, debuggeeName)) { - eventSet.resume(); - } - else { - break; - } - } while (true); - - throw new JDITestRuntimeException("** event IS NOT a breakpoint **"); - } - - - // ============================== test's additional methods private MethodEntryRequest setting23MethodEntryRequest ( ThreadReference thread, diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassExclusionFilter/filter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassExclusionFilter/filter002.java index 3fd039e10d1..4b779448b60 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassExclusionFilter/filter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/MethodExitRequest/addClassExclusionFilter/filter002.java @@ -263,7 +263,7 @@ private void testRun() for (int i = 0; ; i++) { vm.resume(); - breakpointForCommunication(); + breakpointForCommunication(debuggeeName); int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -331,30 +331,6 @@ private void testRun() return; } - protected void breakpointForCommunication() - throws JDITestRuntimeException { - log2("breakpointForCommunication"); - - do { - getEventSet(); - - Event event = eventIterator.nextEvent(); - if (event instanceof BreakpointEvent) - return; - - log2(" received: " + event); - - if (EventFilters.filtered(event, debuggeeName)) { - eventSet.resume(); - } - else { - break; - } - } while (true); - - throw new JDITestRuntimeException("** event IS NOT a breakpoint **"); - } - // ============================== test's additional methods private MethodExitRequest setting23MethodExitRequest ( ThreadReference thread, From e01e33d19b94ee85f7cb7cd6baec857a50086c76 Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Thu, 24 Apr 2025 19:18:13 +0000 Subject: [PATCH 019/118] 8354424: java/util/logging/LoggingDeadlock5.java fails intermittently in tier6 Reviewed-by: dfuchs, smarks --- test/jdk/ProblemList.txt | 1 - test/jdk/java/util/logging/LoggingDeadlock5.java | 11 ++++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 2906cc8da19..b6307d1ed00 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -737,7 +737,6 @@ com/sun/jdi/InvokeHangTest.java 8218463 linux-al # jdk_util java/util/zip/CloseInflaterDeflaterTest.java 8339216 linux-s390x -java/util/logging/LoggingDeadlock5.java 8354424 generic-all ############################################################################ diff --git a/test/jdk/java/util/logging/LoggingDeadlock5.java b/test/jdk/java/util/logging/LoggingDeadlock5.java index fc4639812b7..bff53d1924f 100644 --- a/test/jdk/java/util/logging/LoggingDeadlock5.java +++ b/test/jdk/java/util/logging/LoggingDeadlock5.java @@ -25,11 +25,14 @@ * @test * @bug 8349206 * @summary j.u.l.Handler classes create deadlock risk via synchronized publish() method. + * @library /test/lib * @modules java.base/sun.util.logging * java.logging * @run main/othervm LoggingDeadlock5 */ +import jdk.test.lib.Utils; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -115,7 +118,13 @@ static void assertNoDeadlock(Handler handler) throws InterruptedException, Unsup } private static class DeadLocker { - private final static Duration JOIN_WAIT = Duration.ofMillis(500); + // Since this is used to self-test for an expected deadlock, it will + // delay the test by at least this duration (so being overly large is + // a potential issue). The deadlock is set up so it should occur almost + // immediately (if it occurs), but tests are run under very high loads + // in higher tiers, so it's necessary to be a bit pessimistic here. + private final static Duration JOIN_WAIT = + Duration.ofMillis(Utils.adjustTimeout(2000)); private final Semaphore readyToDeadlock = new Semaphore(0); private final Semaphore userLockIsHeld = new Semaphore(0); From 8a39f07d07f8c4e30dc29b14f28e33c9d8e2e65f Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Thu, 24 Apr 2025 23:23:58 +0000 Subject: [PATCH 020/118] 8354431: gc/logging/TestGCId fails on Shenandoah Reviewed-by: wkemper, phh --- src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 6975bd9f350..d8eb8e0a4e1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -299,7 +299,10 @@ void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cau // Full GC --------------------------/ // ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) return; + if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) { + log_info(gc)("Cancelled"); + return; + } ShenandoahGCSession session(cause, heap->global_generation()); From ed604038ffc4ca64113984324dde71c07f046b52 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Fri, 25 Apr 2025 02:09:58 +0000 Subject: [PATCH 021/118] 8346836: C2: Verify CastII/CastLL bounds at runtime Co-authored-by: Vladimir Ivanov Reviewed-by: vlivanov, epeter --- src/hotspot/cpu/aarch64/aarch64.ad | 28 +++++ .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 104 ++++++++++++++++ .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp | 5 + src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 113 ++++++++++++++++++ src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 6 + src/hotspot/cpu/x86/x86_64.ad | 53 ++++++++ src/hotspot/share/opto/c2_MacroAssembler.hpp | 4 +- src/hotspot/share/opto/c2_globals.hpp | 10 ++ src/hotspot/share/opto/castnode.cpp | 12 ++ .../c2/TestVerifyConstraintCasts.java | 38 ++++++ 10 files changed, 372 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestVerifyConstraintCasts.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 76e3c92ddc2..3d25e97c0c5 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -8144,6 +8144,7 @@ instruct castPP(iRegPNoSp dst) instruct castII(iRegI dst) %{ + predicate(VerifyConstraintCasts == 0); match(Set dst (CastII dst)); size(0); @@ -8153,8 +8154,22 @@ instruct castII(iRegI dst) ins_pipe(pipe_class_empty); %} +instruct castII_checked(iRegI dst, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0); + match(Set dst (CastII dst)); + effect(KILL cr); + + format %{ "# castII_checked of $dst" %} + ins_encode %{ + __ verify_int_in_range(_idx, bottom_type()->is_int(), $dst$$Register, rscratch1); + %} + ins_pipe(pipe_slow); +%} + instruct castLL(iRegL dst) %{ + predicate(VerifyConstraintCasts == 0); match(Set dst (CastLL dst)); size(0); @@ -8164,6 +8179,19 @@ instruct castLL(iRegL dst) ins_pipe(pipe_class_empty); %} +instruct castLL_checked(iRegL dst, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0); + match(Set dst (CastLL dst)); + effect(KILL cr); + + format %{ "# castLL_checked of $dst" %} + ins_encode %{ + __ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, rscratch1); + %} + ins_pipe(pipe_slow); +%} + instruct castFF(vRegF dst) %{ match(Set dst (CastFF dst)); diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 56a91310dcd..585812a99ee 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -2743,3 +2743,107 @@ bool C2_MacroAssembler::in_scratch_emit_size() { } return MacroAssembler::in_scratch_emit_size(); } + +static void abort_verify_int_in_range(uint idx, jint val, jint lo, jint hi) { + fatal("Invalid CastII, idx: %u, val: %d, lo: %d, hi: %d", idx, val, lo, hi); +} + +void C2_MacroAssembler::verify_int_in_range(uint idx, const TypeInt* t, Register rval, Register rtmp) { + assert(!t->empty() && !t->singleton(), "%s", Type::str(t)); + if (t == TypeInt::INT) { + return; + } + BLOCK_COMMENT("verify_int_in_range {"); + Label L_success, L_failure; + + jint lo = t->_lo; + jint hi = t->_hi; + + if (lo != min_jint && hi != max_jint) { + subsw(rtmp, rval, lo); + br(Assembler::LT, L_failure); + subsw(rtmp, rval, hi); + br(Assembler::LE, L_success); + } else if (lo != min_jint) { + subsw(rtmp, rval, lo); + br(Assembler::GE, L_success); + } else if (hi != max_jint) { + subsw(rtmp, rval, hi); + br(Assembler::LE, L_success); + } else { + ShouldNotReachHere(); + } + + bind(L_failure); + movw(c_rarg0, idx); + mov(c_rarg1, rval); + movw(c_rarg2, lo); + movw(c_rarg3, hi); + reconstruct_frame_pointer(rtmp); + rt_call(CAST_FROM_FN_PTR(address, abort_verify_int_in_range), rtmp); + hlt(0); + + bind(L_success); + BLOCK_COMMENT("} verify_int_in_range"); +} + +static void abort_verify_long_in_range(uint idx, jlong val, jlong lo, jlong hi) { + fatal("Invalid CastLL, idx: %u, val: " JLONG_FORMAT ", lo: " JLONG_FORMAT ", hi: " JLONG_FORMAT, idx, val, lo, hi); +} + +void C2_MacroAssembler::verify_long_in_range(uint idx, const TypeLong* t, Register rval, Register rtmp) { + assert(!t->empty() && !t->singleton(), "%s", Type::str(t)); + if (t == TypeLong::LONG) { + return; + } + BLOCK_COMMENT("verify_long_in_range {"); + Label L_success, L_failure; + + jlong lo = t->_lo; + jlong hi = t->_hi; + + if (lo != min_jlong && hi != max_jlong) { + subs(rtmp, rval, lo); + br(Assembler::LT, L_failure); + subs(rtmp, rval, hi); + br(Assembler::LE, L_success); + } else if (lo != min_jlong) { + subs(rtmp, rval, lo); + br(Assembler::GE, L_success); + } else if (hi != max_jlong) { + subs(rtmp, rval, hi); + br(Assembler::LE, L_success); + } else { + ShouldNotReachHere(); + } + + bind(L_failure); + movw(c_rarg0, idx); + mov(c_rarg1, rval); + mov(c_rarg2, lo); + mov(c_rarg3, hi); + reconstruct_frame_pointer(rtmp); + rt_call(CAST_FROM_FN_PTR(address, abort_verify_long_in_range), rtmp); + hlt(0); + + bind(L_success); + BLOCK_COMMENT("} verify_long_in_range"); +} + +void C2_MacroAssembler::reconstruct_frame_pointer(Register rtmp) { + const int framesize = Compile::current()->output()->frame_size_in_bytes(); + if (PreserveFramePointer) { + // frame pointer is valid +#ifdef ASSERT + // Verify frame pointer value in rfp. + add(rtmp, sp, framesize - 2 * wordSize); + Label L_success; + cmp(rfp, rtmp); + br(Assembler::EQ, L_success); + stop("frame pointer mismatch"); + bind(L_success); +#endif // ASSERT + } else { + add(rfp, sp, framesize - 2 * wordSize); + } +} diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index e0eaa0b76e6..70e4265c7cc 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -188,4 +188,9 @@ void vector_signum_sve(FloatRegister dst, FloatRegister src, FloatRegister zero, FloatRegister one, FloatRegister vtmp, PRegister pgtmp, SIMD_RegVariant T); + void verify_int_in_range(uint idx, const TypeInt* t, Register val, Register tmp); + void verify_long_in_range(uint idx, const TypeLong* t, Register val, Register tmp); + + void reconstruct_frame_pointer(Register rtmp); + #endif // CPU_AARCH64_C2_MACROASSEMBLER_AARCH64_HPP diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 574bc081fce..19e25cde2ec 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -787,6 +787,119 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, // C2 uses the value of ZF to determine the continuation. } +static void abort_verify_int_in_range(uint idx, jint val, jint lo, jint hi) { + fatal("Invalid CastII, idx: %u, val: %d, lo: %d, hi: %d", idx, val, lo, hi); +} + +static void reconstruct_frame_pointer_helper(MacroAssembler* masm, Register dst) { + const int framesize = Compile::current()->output()->frame_size_in_bytes(); + masm->movptr(dst, rsp); + if (framesize > 2 * wordSize) { + masm->addptr(dst, framesize - 2 * wordSize); + } +} + +void C2_MacroAssembler::reconstruct_frame_pointer(Register rtmp) { + if (PreserveFramePointer) { + // frame pointer is valid +#ifdef ASSERT + // Verify frame pointer value in rbp. + reconstruct_frame_pointer_helper(this, rtmp); + Label L_success; + cmpq(rbp, rtmp); + jccb(Assembler::equal, L_success); + STOP("frame pointer mismatch"); + bind(L_success); +#endif // ASSERT + } else { + reconstruct_frame_pointer_helper(this, rbp); + } +} + +void C2_MacroAssembler::verify_int_in_range(uint idx, const TypeInt* t, Register val) { + jint lo = t->_lo; + jint hi = t->_hi; + assert(lo < hi, "type should not be empty or constant, idx: %u, lo: %d, hi: %d", idx, lo, hi); + if (t == TypeInt::INT) { + return; + } + + BLOCK_COMMENT("CastII {"); + Label fail; + Label succeed; + if (hi == max_jint) { + cmpl(val, lo); + jccb(Assembler::greaterEqual, succeed); + } else { + if (lo != min_jint) { + cmpl(val, lo); + jccb(Assembler::less, fail); + } + cmpl(val, hi); + jccb(Assembler::lessEqual, succeed); + } + + bind(fail); + movl(c_rarg0, idx); + movl(c_rarg1, val); + movl(c_rarg2, lo); + movl(c_rarg3, hi); + reconstruct_frame_pointer(rscratch1); + call(RuntimeAddress(CAST_FROM_FN_PTR(address, abort_verify_int_in_range))); + hlt(); + bind(succeed); + BLOCK_COMMENT("} // CastII"); +} + +static void abort_verify_long_in_range(uint idx, jlong val, jlong lo, jlong hi) { + fatal("Invalid CastLL, idx: %u, val: " JLONG_FORMAT ", lo: " JLONG_FORMAT ", hi: " JLONG_FORMAT, idx, val, lo, hi); +} + +void C2_MacroAssembler::verify_long_in_range(uint idx, const TypeLong* t, Register val, Register tmp) { + jlong lo = t->_lo; + jlong hi = t->_hi; + assert(lo < hi, "type should not be empty or constant, idx: %u, lo: " JLONG_FORMAT ", hi: " JLONG_FORMAT, idx, lo, hi); + if (t == TypeLong::LONG) { + return; + } + + BLOCK_COMMENT("CastLL {"); + Label fail; + Label succeed; + + auto cmp_val = [&](jlong bound) { + if (is_simm32(bound)) { + cmpq(val, checked_cast(bound)); + } else { + mov64(tmp, bound); + cmpq(val, tmp); + } + }; + + if (hi == max_jlong) { + cmp_val(lo); + jccb(Assembler::greaterEqual, succeed); + } else { + if (lo != min_jlong) { + cmp_val(lo); + jccb(Assembler::less, fail); + } + cmp_val(hi); + jccb(Assembler::lessEqual, succeed); + } + + bind(fail); + movl(c_rarg0, idx); + movq(c_rarg1, val); + mov64(c_rarg2, lo); + mov64(c_rarg3, hi); + reconstruct_frame_pointer(rscratch1); + call(RuntimeAddress(CAST_FROM_FN_PTR(address, abort_verify_long_in_range))); + hlt(); + bind(succeed); + BLOCK_COMMENT("} // CastLL"); +} + //------------------------------------------------------------------------------------------- // Generic instructions support for use in .ad files C2 code generation diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index dd2880d88c3..713eb73d68f 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -44,6 +44,9 @@ Register t, Register thread); void fast_unlock_lightweight(Register obj, Register reg_rax, Register t, Register thread); + void verify_int_in_range(uint idx, const TypeInt* t, Register val); + void verify_long_in_range(uint idx, const TypeLong* t, Register val, Register tmp); + // Generic instructions support for use in .ad files C2 code generation void vabsnegd(int opcode, XMMRegister dst, XMMRegister src); void vabsnegd(int opcode, XMMRegister dst, XMMRegister src, int vector_len); @@ -574,4 +577,7 @@ void scalar_max_min_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2); + + void reconstruct_frame_pointer(Register rtmp); + #endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 078150c61fb..dc79108c6f8 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -422,6 +422,18 @@ source_hpp %{ #include "peephole_x86_64.hpp" +bool castLL_is_imm32(const Node* n); + +%} + +source %{ + +bool castLL_is_imm32(const Node* n) { + assert(n->is_CastLL(), "must be a CastLL"); + const TypeLong* t = n->bottom_type()->is_long(); + return (t->_lo == min_jlong || Assembler::is_simm32(t->_lo)) && (t->_hi == max_jlong || Assembler::is_simm32(t->_hi)); +} + %} // Register masks @@ -7605,6 +7617,7 @@ instruct castPP(rRegP dst) instruct castII(rRegI dst) %{ + predicate(VerifyConstraintCasts == 0); match(Set dst (CastII dst)); size(0); @@ -7614,8 +7627,22 @@ instruct castII(rRegI dst) ins_pipe(empty); %} +instruct castII_checked(rRegI dst, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0); + match(Set dst (CastII dst)); + + effect(KILL cr); + format %{ "# cast_checked_II $dst" %} + ins_encode %{ + __ verify_int_in_range(_idx, bottom_type()->is_int(), $dst$$Register); + %} + ins_pipe(pipe_slow); +%} + instruct castLL(rRegL dst) %{ + predicate(VerifyConstraintCasts == 0); match(Set dst (CastLL dst)); size(0); @@ -7625,6 +7652,32 @@ instruct castLL(rRegL dst) ins_pipe(empty); %} +instruct castLL_checked_L32(rRegL dst, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0 && castLL_is_imm32(n)); + match(Set dst (CastLL dst)); + + effect(KILL cr); + format %{ "# cast_checked_LL $dst" %} + ins_encode %{ + __ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, noreg); + %} + ins_pipe(pipe_slow); +%} + +instruct castLL_checked(rRegL dst, rRegL tmp, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0 && !castLL_is_imm32(n)); + match(Set dst (CastLL dst)); + + effect(KILL cr, TEMP tmp); + format %{ "# cast_checked_LL $dst\tusing $tmp as TEMP" %} + ins_encode %{ + __ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, $tmp$$Register); + %} + ins_pipe(pipe_slow); +%} + instruct castFF(regF dst) %{ match(Set dst (CastFF dst)); diff --git a/src/hotspot/share/opto/c2_MacroAssembler.hpp b/src/hotspot/share/opto/c2_MacroAssembler.hpp index 41347313a8c..1fb7714153d 100644 --- a/src/hotspot/share/opto/c2_MacroAssembler.hpp +++ b/src/hotspot/share/opto/c2_MacroAssembler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,8 @@ #include "utilities/macros.hpp" class C2EntryBarrierStub; +class TypeInt; +class TypeLong; class C2_MacroAssembler: public MacroAssembler { public: diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 41b08161097..662f2e07965 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -669,6 +669,16 @@ develop(bool, VerifyAliases, false, \ "perform extra checks on the results of alias analysis") \ \ + product(uint, VerifyConstraintCasts, 0, DIAGNOSTIC, \ + "Perform runtime checks to verify the value of a " \ + "ConstraintCast lies inside its type" \ + "0 = does not perform any verification, " \ + "1 = perform verification on ConstraintCastNodes that are " \ + "present during code emission, " \ + "2 = Do not do widening of ConstraintCastNodes so that we can " \ + "have more verification coverage") \ + range(0, 2) \ + \ product(intx, MaxInlineLevel, 15, \ "maximum number of nested calls that are inlined by high tier " \ "compiler") \ diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 198634af71b..6b3058d94f6 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -531,6 +531,18 @@ const Type* ConstraintCastNode::widen_type(const PhaseGVN* phase, const Type* re if (!phase->C->post_loop_opts_phase()) { return res; } + + // At VerifyConstraintCasts == 1, we verify the ConstraintCastNodes that are present during code + // emission. This allows us detecting possible mis-scheduling due to these nodes being pinned at + // the wrong control nodes. + // At VerifyConstraintCasts == 2, we do not perform widening so that we can verify the + // correctness of more ConstraintCastNodes. This further helps us detect possible + // mis-transformations that may happen due to these nodes being pinned at the wrong control + // nodes. + if (VerifyConstraintCasts > 1) { + return res; + } + const TypeInteger* this_type = res->is_integer(bt); const TypeInteger* in_type = phase->type(in(1))->isa_integer(bt); if (in_type != nullptr && diff --git a/test/hotspot/jtreg/compiler/c2/TestVerifyConstraintCasts.java b/test/hotspot/jtreg/compiler/c2/TestVerifyConstraintCasts.java new file mode 100644 index 00000000000..5c8a367c97c --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestVerifyConstraintCasts.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8346836 + * @requires vm.debug == true & vm.flavor == "server" + * @summary Empty main program to run with flag VerifyConstraintCasts. + * + * @run main/othervm/timeout=300 -Xbatch -Xcomp -XX:+StressGCM -XX:VerifyConstraintCasts=1 compiler.c2.TestVerifyConstraintCasts + * @run main/othervm/timeout=300 -Xbatch -Xcomp -XX:+StressGCM -XX:VerifyConstraintCasts=2 compiler.c2.TestVerifyConstraintCasts + */ +package compiler.c2; + +public class TestVerifyConstraintCasts { + public static void main(String[] args) { + } +} From f27fc010f699c01bd3c633b2926966578b5da270 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Fri, 25 Apr 2025 07:09:10 +0000 Subject: [PATCH 022/118] 8355576: Problem list compiler/c2/TestVerifyConstraintCasts.java until JDK-8355574 is fixed 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 d76f4b2d95b..d4276946360 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -76,6 +76,8 @@ compiler/interpreter/Test6833129.java 8335266 generic-i586 compiler/ciReplay/TestInliningProtectionDomain.java 8349191 generic-all compiler/ciReplay/TestIncrementalInlining.java 8349191 generic-all +compiler/c2/TestVerifyConstraintCasts.java 8355574 generic-all + ############################################################################# # :hotspot_gc From 70030bac04b99454af7577553e4a6bbaf5d39210 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 25 Apr 2025 07:09:37 +0000 Subject: [PATCH 023/118] 8354803: ALL_64_BITS is the same across platforms Reviewed-by: stefank, lucy --- src/hotspot/os/aix/os_aix.cpp | 8 +++----- src/hotspot/os/bsd/os_bsd.cpp | 9 +++------ src/hotspot/os/linux/os_linux.cpp | 7 ++----- src/hotspot/os/posix/os_posix.cpp | 5 +---- src/hotspot/os/windows/os_windows.cpp | 13 +++++-------- src/hotspot/share/utilities/globalDefinitions.hpp | 3 +++ 6 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 49dcebd0083..1bbaf29125d 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -132,8 +132,6 @@ extern "C" int getargs(procsinfo*, int, char*, int); #define MAX_PATH (2 * K) -// for timer info max values which include all bits -#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) // for multipage initialization error analysis (in 'g_multipage_error') #define ERROR_MP_OS_TOO_OLD 100 #define ERROR_MP_EXTSHM_ACTIVE 101 @@ -906,7 +904,7 @@ jlong os::javaTimeNanos() { } void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; + info_ptr->max_value = all_bits_jlong; // mread_real_time() is monotonic (see 'os::javaTimeNanos()') info_ptr->may_skip_backward = false; info_ptr->may_skip_forward = false; @@ -2571,14 +2569,14 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned } void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 193c7cb0689..9a9954b3eb9 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -114,9 +114,6 @@ #define MAX_PATH (2 * K) -// for timer info max values which include all bits -#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) - //////////////////////////////////////////////////////////////////////////////// // global variables julong os::Bsd::_physical_memory = 0; @@ -815,7 +812,7 @@ jlong os::javaTimeNanos() { } void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; + info_ptr->max_value = all_bits_jlong; info_ptr->may_skip_backward = false; // not subject to resetting or drifting info_ptr->may_skip_forward = false; // not subject to resetting or drifting info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time @@ -2423,14 +2420,14 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned } void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 1afece719cb..029d523edc6 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -139,9 +139,6 @@ #define MAX_PATH (2 * K) -// for timer info max values which include all bits -#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) - #ifdef MUSL_LIBC // dlvsym is not a part of POSIX // and musl libc doesn't implement it. @@ -5142,14 +5139,14 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned } void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index df084ae6898..b399ce4bcbf 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1473,12 +1473,9 @@ jlong os::javaTimeNanos() { return result; } -// for timer info max values which include all bits -#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) - void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { // CLOCK_MONOTONIC - amount of time since some arbitrary point in the past - info_ptr->max_value = ALL_64_BITS; + info_ptr->max_value = all_bits_jlong; info_ptr->may_skip_backward = false; // not subject to resetting or drifting info_ptr->may_skip_forward = false; // not subject to resetting or drifting info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 959a0616834..55ad3bf840d 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -112,9 +112,6 @@ #include #include -// for timer info max values which include all bits -#define ALL_64_BITS CONST64(-1) - // For DLL loading/load error detection // Values of PE COFF #define IMAGE_FILE_PTR_TO_SIGNATURE 0x3c @@ -1225,16 +1222,16 @@ void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { if (freq < NANOSECS_PER_SEC) { // the performance counter is 64 bits and we will // be multiplying it -- so no wrap in 64 bits - info_ptr->max_value = ALL_64_BITS; + info_ptr->max_value = all_bits_jlong; } else if (freq > NANOSECS_PER_SEC) { // use the max value the counter can reach to // determine the max value which could be returned - julong max_counter = (julong)ALL_64_BITS; + julong max_counter = (julong)all_bits_jlong; info_ptr->max_value = (jlong)(max_counter / (freq / NANOSECS_PER_SEC)); } else { // the performance counter is 64 bits and we will // be using it directly -- so no wrap in 64 bits - info_ptr->max_value = ALL_64_BITS; + info_ptr->max_value = all_bits_jlong; } // using a counter, so no skipping @@ -4813,14 +4810,14 @@ jlong os::thread_cpu_time(Thread* thread, bool user_sys_cpu_time) { } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // the max value -- all 64 bits + info_ptr->max_value = all_bits_jlong; // the max value -- all 64 bits info_ptr->may_skip_backward = false; // GetThreadTimes returns absolute time info_ptr->may_skip_forward = false; // GetThreadTimes returns absolute time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned } void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // the max value -- all 64 bits + info_ptr->max_value = all_bits_jlong; // the max value -- all 64 bits info_ptr->may_skip_backward = false; // GetThreadTimes returns absolute time info_ptr->may_skip_forward = false; // GetThreadTimes returns absolute time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 085939b0131..cc5f3ebb291 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -269,6 +269,9 @@ inline jdouble jdouble_cast(jlong x); const jlong min_jlong = CONST64(0x8000000000000000); const jlong max_jlong = CONST64(0x7fffffffffffffff); +// for timer info max values which include all bits, 0xffffffffffffffff +const jlong all_bits_jlong = ~jlong(0); + //------------------------------------------- // Constant for jdouble const jlong min_jlongDouble = CONST64(0x0000000000000001); From dbd2fb0e5a06df2760a6c4ac128a9172b13647d9 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 25 Apr 2025 07:11:24 +0000 Subject: [PATCH 024/118] 8355473: Clean up x86 globals/VM_Version after 32-bit x86 removal Reviewed-by: chagedorn, coleenp, jwaters --- src/hotspot/cpu/x86/globalDefinitions_x86.hpp | 6 - src/hotspot/cpu/x86/globals_x86.hpp | 12 +- src/hotspot/cpu/x86/vm_version_x86.cpp | 156 ++---------------- src/hotspot/cpu/x86/vm_version_x86.hpp | 10 +- 4 files changed, 17 insertions(+), 167 deletions(-) diff --git a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp index 873cfbdcea0..3c1474ae861 100644 --- a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp +++ b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp @@ -34,9 +34,7 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define SUPPORTS_NATIVE_CX8 -#ifdef _LP64 #define SUPPORT_MONITOR_COUNT -#endif #define CPU_MULTI_COPY_ATOMIC @@ -44,15 +42,11 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define DEFAULT_CACHE_LINE_SIZE 64 // The default padding size for data structures to avoid false sharing. -#ifdef _LP64 // The common wisdom is that adjacent cache line prefetchers on some hardware // may pull two cache lines on access, so we have to pessimistically assume twice // the cache line size for padding. TODO: Check if this is still true for modern // hardware. If not, DEFAULT_CACHE_LINE_SIZE might as well suffice. #define DEFAULT_PADDING_SIZE (DEFAULT_CACHE_LINE_SIZE*2) -#else -#define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE -#endif #if defined(LINUX) || defined(__APPLE__) #define SUPPORT_RESERVED_STACK_AREA diff --git a/src/hotspot/cpu/x86/globals_x86.hpp b/src/hotspot/cpu/x86/globals_x86.hpp index 5b5f5683961..a1d4a71874f 100644 --- a/src/hotspot/cpu/x86/globals_x86.hpp +++ b/src/hotspot/cpu/x86/globals_x86.hpp @@ -61,29 +61,19 @@ define_pd_global(intx, InlineSmallCode, 1000); #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES #define MIN_STACK_RESERVED_PAGES (0) -#ifdef _LP64 // Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the -// stack if compiled for unix and LP64. To pass stack overflow tests we need -// 20 shadow pages. +// stack if compiled for unix. To pass stack overflow tests we need 20 shadow pages. #define DEFAULT_STACK_SHADOW_PAGES (NOT_WIN64(20) WIN64_ONLY(8) DEBUG_ONLY(+4)) // For those clients that do not use write socket, we allow // the min range value to be below that of the default #define MIN_STACK_SHADOW_PAGES (NOT_WIN64(10) WIN64_ONLY(8) DEBUG_ONLY(+4)) -#else -#define DEFAULT_STACK_SHADOW_PAGES (4 DEBUG_ONLY(+5)) -#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES -#endif // _LP64 define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); -#ifdef _LP64 define_pd_global(bool, VMContinuations, true); -#else -define_pd_global(bool, VMContinuations, false); -#endif define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 19ae2dc8d2b..4687edb13a3 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -72,8 +72,6 @@ static get_cpu_info_stub_t get_cpu_info_stub = nullptr; static detect_virt_stub_t detect_virt_stub = nullptr; static clear_apx_test_state_t clear_apx_test_state_stub = nullptr; -#ifdef _LP64 - bool VM_Version::supports_clflush() { // clflush should always be available on x86_64 // if not we are in real trouble because we rely on it @@ -87,7 +85,6 @@ bool VM_Version::supports_clflush() { assert ((!Universe::is_fully_initialized() || (_features & CPU_FLUSH) != 0), "clflush should be available"); return true; } -#endif #define CPUID_STANDARD_FN 0x0 #define CPUID_STANDARD_FN_1 0x1 @@ -107,7 +104,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator { VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {} -#if defined(_LP64) address clear_apx_test_state() { # define __ _masm-> address start = __ pc(); @@ -126,7 +122,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ ret(0); return start; } -#endif address generate_get_cpu_info() { // Flags to test CPU type. @@ -151,14 +146,10 @@ class VM_Version_StubGenerator: public StubCodeGenerator { // // void get_cpu_info(VM_Version::CpuidInfo* cpuid_info); // - // LP64: rcx and rdx are first and second argument registers on windows + // rcx and rdx are first and second argument registers on windows __ push(rbp); -#ifdef _LP64 __ mov(rbp, c_rarg0); // cpuid_info address -#else - __ movptr(rbp, Address(rsp, 8)); // cpuid_info address -#endif __ push(rbx); __ push(rsi); __ pushf(); // preserve rbx, and flags @@ -418,7 +409,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movl(Address(rsi, 8), rcx); __ movl(Address(rsi,12), rdx); -#if defined(_LP64) // // Check if OS has enabled XGETBV instruction to access XCR0 // (OSXSAVE feature flag) and CPU supports APX @@ -453,7 +443,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movq(Address(rsi, 8), r31); UseAPX = save_apx; -#endif #endif __ bind(vector_save_restore); // @@ -527,10 +516,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movdl(xmm0, rcx); __ vpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit); __ evmovdqul(xmm7, xmm0, Assembler::AVX_512bit); -#ifdef _LP64 __ evmovdqul(xmm8, xmm0, Assembler::AVX_512bit); __ evmovdqul(xmm31, xmm0, Assembler::AVX_512bit); -#endif VM_Version::clean_cpuFeatures(); __ jmp(save_restore_except); } @@ -556,10 +543,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ pshufd(xmm0, xmm0, 0x00); __ vinsertf128_high(xmm0, xmm0); __ vmovdqu(xmm7, xmm0); -#ifdef _LP64 __ vmovdqu(xmm8, xmm0); __ vmovdqu(xmm15, xmm0); -#endif VM_Version::clean_cpuFeatures(); __ bind(save_restore_except); @@ -600,10 +585,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ lea(rsi, Address(rbp, in_bytes(VM_Version::zmm_save_offset()))); __ evmovdqul(Address(rsi, 0), xmm0, Assembler::AVX_512bit); __ evmovdqul(Address(rsi, 64), xmm7, Assembler::AVX_512bit); -#ifdef _LP64 __ evmovdqul(Address(rsi, 128), xmm8, Assembler::AVX_512bit); __ evmovdqul(Address(rsi, 192), xmm31, Assembler::AVX_512bit); -#endif #ifdef _WINDOWS __ evmovdqul(xmm31, Address(rsp, 0), Assembler::AVX_512bit); @@ -628,10 +611,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ lea(rsi, Address(rbp, in_bytes(VM_Version::ymm_save_offset()))); __ vmovdqu(Address(rsi, 0), xmm0); __ vmovdqu(Address(rsi, 32), xmm7); -#ifdef _LP64 __ vmovdqu(Address(rsi, 64), xmm8); __ vmovdqu(Address(rsi, 96), xmm15); -#endif #ifdef _WINDOWS __ vmovdqu(xmm15, Address(rsp, 0)); @@ -687,13 +668,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ push(rbx); __ push(rsi); // for Windows -#ifdef _LP64 __ mov(rax, c_rarg0); // CPUID leaf __ mov(rsi, c_rarg1); // register array address (eax, ebx, ecx, edx) -#else - __ movptr(rax, Address(rsp, 16)); // CPUID leaf - __ movptr(rsi, Address(rsp, 20)); // register array address -#endif __ cpuid(); @@ -734,14 +710,10 @@ class VM_Version_StubGenerator: public StubCodeGenerator { // // void getCPUIDBrandString(VM_Version::CpuidInfo* cpuid_info); // - // LP64: rcx and rdx are first and second argument registers on windows + // rcx and rdx are first and second argument registers on windows __ push(rbp); -#ifdef _LP64 __ mov(rbp, c_rarg0); // cpuid_info address -#else - __ movptr(rbp, Address(rsp, 8)); // cpuid_info address -#endif __ push(rbx); __ push(rsi); __ pushf(); // preserve rbx, and flags @@ -889,19 +861,16 @@ void VM_Version::get_processor_features() { // xchg and xadd instructions _supports_atomic_getset4 = true; _supports_atomic_getadd4 = true; - LP64_ONLY(_supports_atomic_getset8 = true); - LP64_ONLY(_supports_atomic_getadd8 = true); + _supports_atomic_getset8 = true; + _supports_atomic_getadd8 = true; -#ifdef _LP64 // OS should support SSE for x64 and hardware should support at least SSE2. if (!VM_Version::supports_sse2()) { vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported"); } // in 64 bit the use of SSE2 is the minimum if (UseSSE < 2) UseSSE = 2; -#endif -#ifdef AMD64 // flush_icache_stub have to be generated first. // That is why Icache line size is hard coded in ICache class, // see icache_x86.hpp. It is also the reason why we can't use @@ -913,9 +882,7 @@ void VM_Version::get_processor_features() { guarantee(_cpuid_info.std_cpuid1_edx.bits.clflush != 0, "clflush is not supported"); // clflush_size is size in quadwords (8 bytes). guarantee(_cpuid_info.std_cpuid1_ebx.bits.clflush_size == 8, "such clflush size is not supported"); -#endif -#ifdef _LP64 // assigning this field effectively enables Unsafe.writebackMemory() // by initing UnsafeConstant.DATA_CACHE_LINE_FLUSH_SIZE to non-zero // that is only implemented on x86_64 and only if the OS plays ball @@ -924,7 +891,6 @@ void VM_Version::get_processor_features() { // let if default to zero thereby disabling writeback _data_cache_line_flush_size = _cpuid_info.std_cpuid1_ebx.bits.clflush_size * 8; } -#endif // Check if processor has Intel Ecore if (FLAG_IS_DEFAULT(EnableX86ECoreOpts) && is_intel() && cpu_family() == 6 && @@ -1206,7 +1172,6 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } -#ifdef _LP64 if (supports_avx2()) { if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) { UseAdler32Intrinsics = true; @@ -1217,12 +1182,6 @@ void VM_Version::get_processor_features() { } FLAG_SET_DEFAULT(UseAdler32Intrinsics, false); } -#else - if (UseAdler32Intrinsics) { - warning("Adler32Intrinsics not available on this CPU."); - FLAG_SET_DEFAULT(UseAdler32Intrinsics, false); - } -#endif if (supports_sse4_2() && supports_clmul()) { if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { @@ -1246,7 +1205,6 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); } -#ifdef _LP64 // ChaCha20 Intrinsics // As long as the system supports AVX as a baseline we can do a // SIMD-enabled block function. StubGenerator makes the determination @@ -1262,24 +1220,14 @@ void VM_Version::get_processor_features() { } FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); } -#else - // No support currently for ChaCha20 intrinsics on 32-bit platforms - if (UseChaCha20Intrinsics) { - warning("ChaCha20 intrinsics are not available on this CPU."); - FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); - } -#endif // _LP64 // Dilithium Intrinsics // Currently we only have them for AVX512 -#ifdef _LP64 if (supports_evex() && supports_avx512bw()) { if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { UseDilithiumIntrinsics = true; } - } else -#endif - if (UseDilithiumIntrinsics) { + } else if (UseDilithiumIntrinsics) { warning("Intrinsics for ML-DSA are not available on this CPU."); FLAG_SET_DEFAULT(UseDilithiumIntrinsics, false); } @@ -1308,7 +1256,7 @@ void VM_Version::get_processor_features() { UseMD5Intrinsics = true; } - if (supports_sha() LP64_ONLY(|| (supports_avx2() && supports_bmi2()))) { + if (supports_sha() || (supports_avx2() && supports_bmi2())) { if (FLAG_IS_DEFAULT(UseSHA)) { UseSHA = true; } @@ -1335,27 +1283,20 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); } -#ifdef _LP64 - // These are only supported on 64-bit if (UseSHA && supports_avx2() && (supports_bmi2() || supports_sha512())) { if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) { FLAG_SET_DEFAULT(UseSHA512Intrinsics, true); } - } else -#endif - if (UseSHA512Intrinsics) { + } else if (UseSHA512Intrinsics) { warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } -#ifdef _LP64 if (supports_evex() && supports_avx512bw()) { if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) { UseSHA3Intrinsics = true; } - } else -#endif - if (UseSHA3Intrinsics) { + } else if (UseSHA3Intrinsics) { warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); } @@ -1377,11 +1318,7 @@ void VM_Version::get_processor_features() { max_vector_size = 64; } -#ifdef _LP64 int min_vector_size = 4; // We require MaxVectorSize to be at least 4 on 64bit -#else - int min_vector_size = 0; -#endif if (!FLAG_IS_DEFAULT(MaxVectorSize)) { if (MaxVectorSize < min_vector_size) { @@ -1405,7 +1342,7 @@ void VM_Version::get_processor_features() { if (MaxVectorSize > 0) { if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) { tty->print_cr("State of YMM registers after signal handle:"); - int nreg = 2 LP64_ONLY(+2); + int nreg = 4; const char* ymm_name[4] = {"0", "7", "8", "15"}; for (int i = 0; i < nreg; i++) { tty->print("YMM%s:", ymm_name[i]); @@ -1418,31 +1355,24 @@ void VM_Version::get_processor_features() { } #endif // COMPILER2 && ASSERT -#ifdef _LP64 if ((supports_avx512ifma() && supports_avx512vlbw()) || supports_avxifma()) { if (FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) { FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true); } - } else -#endif - if (UsePoly1305Intrinsics) { + } else if (UsePoly1305Intrinsics) { warning("Intrinsics for Poly1305 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UsePoly1305Intrinsics, false); } -#ifdef _LP64 if ((supports_avx512ifma() && supports_avx512vlbw()) || supports_avxifma()) { if (FLAG_IS_DEFAULT(UseIntPolyIntrinsics)) { FLAG_SET_DEFAULT(UseIntPolyIntrinsics, true); } - } else -#endif - if (UseIntPolyIntrinsics) { + } else if (UseIntPolyIntrinsics) { warning("Intrinsics for Polynomial crypto functions not available on this CPU."); FLAG_SET_DEFAULT(UseIntPolyIntrinsics, false); } -#ifdef _LP64 if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { UseMultiplyToLenIntrinsic = true; } @@ -1458,38 +1388,6 @@ void VM_Version::get_processor_features() { if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { UseMontgomerySquareIntrinsic = true; } -#else - if (UseMultiplyToLenIntrinsic) { - if (!FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { - warning("multiplyToLen intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false); - } - if (UseMontgomeryMultiplyIntrinsic) { - if (!FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) { - warning("montgomeryMultiply intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, false); - } - if (UseMontgomerySquareIntrinsic) { - if (!FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { - warning("montgomerySquare intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, false); - } - if (UseSquareToLenIntrinsic) { - if (!FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { - warning("squareToLen intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, false); - } - if (UseMulAddIntrinsic) { - if (!FLAG_IS_DEFAULT(UseMulAddIntrinsic)) { - warning("mulAdd intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseMulAddIntrinsic, false); - } -#endif // _LP64 #endif // COMPILER2_OR_JVMCI // On new cpus instructions which update whole XMM register should be used @@ -1766,7 +1664,6 @@ void VM_Version::get_processor_features() { } #endif -#ifdef _LP64 if (UseSSE42Intrinsics) { if (FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) { UseVectorizedMismatchIntrinsic = true; @@ -1783,20 +1680,6 @@ void VM_Version::get_processor_features() { warning("vectorizedHashCode intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, false); } -#else - if (UseVectorizedMismatchIntrinsic) { - if (!FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) { - warning("vectorizedMismatch intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); - } - if (UseVectorizedHashCodeIntrinsic) { - if (!FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) { - warning("vectorizedHashCode intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, false); - } -#endif // _LP64 // Use count leading zeros count instruction if available. if (supports_lzcnt()) { @@ -1945,7 +1828,6 @@ void VM_Version::get_processor_features() { #endif } -#ifdef _LP64 // Prefetch settings // Prefetch interval for gc copy/scan == 9 dcache lines. Derived from @@ -1964,7 +1846,6 @@ void VM_Version::get_processor_features() { if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes)) { FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 576); } -#endif if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && (cache_line_size > ContendedPaddingWidth)) @@ -2195,11 +2076,9 @@ int VM_Version::avx3_threshold() { FLAG_IS_DEFAULT(AVX3Threshold)) ? 0 : AVX3Threshold; } -#if defined(_LP64) void VM_Version::clear_apx_test_state() { clear_apx_test_state_stub(); } -#endif static bool _vm_version_initialized = false; @@ -2217,14 +2096,11 @@ void VM_Version::initialize() { g.generate_get_cpu_info()); detect_virt_stub = CAST_TO_FN_PTR(detect_virt_stub_t, g.generate_detect_virt()); - -#if defined(_LP64) clear_apx_test_state_stub = CAST_TO_FN_PTR(clear_apx_test_state_t, g.clear_apx_test_state()); -#endif get_processor_features(); - LP64_ONLY(Assembler::precompute_instructions();) + Assembler::precompute_instructions(); if (VM_Version::supports_hv()) { // Supports hypervisor check_virtualizations(); @@ -2991,12 +2867,10 @@ uint64_t VM_Version::CpuidInfo::feature_flags() const { result |= CPU_CMOV; if (std_cpuid1_edx.bits.clflush != 0) result |= CPU_FLUSH; -#ifdef _LP64 // clflush should always be available on x86_64 // if not we are in real trouble because we rely on it // to flush the code cache. assert ((result & CPU_FLUSH) != 0, "clflush should be available"); -#endif if (std_cpuid1_edx.bits.fxsr != 0 || (is_amd_family() && ext_cpuid1_edx.bits.fxsr != 0)) result |= CPU_FXSR; @@ -3168,7 +3042,7 @@ uint64_t VM_Version::CpuidInfo::feature_flags() const { bool VM_Version::os_supports_avx_vectors() { bool retVal = false; - int nreg = 2 LP64_ONLY(+2); + int nreg = 4; if (supports_evex()) { // Verify that OS save/restore all bits of EVEX registers // during signal processing. @@ -3324,11 +3198,7 @@ int VM_Version::allocate_prefetch_distance(bool use_watermark_prefetch) { if (supports_sse4_2() && supports_ht()) { // Nehalem based cpus return 192; } else if (use_watermark_prefetch) { // watermark prefetching on Core -#ifdef _LP64 return 384; -#else - return 320; -#endif } } if (supports_sse2()) { diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index cc5c6c1c639..7eb627c8714 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -642,7 +642,7 @@ class VM_Version : public Abstract_VM_Version { static void set_cpuinfo_cont_addr_apx(address pc) { _cpuinfo_cont_addr_apx = pc; } static address cpuinfo_cont_addr_apx() { return _cpuinfo_cont_addr_apx; } - LP64_ONLY(static void clear_apx_test_state()); + static void clear_apx_test_state(); static void clean_cpuFeatures() { _features = 0; } static void set_avx_cpuFeatures() { _features |= (CPU_SSE | CPU_SSE2 | CPU_AVX | CPU_VZEROUPPER ); } @@ -839,12 +839,12 @@ class VM_Version : public Abstract_VM_Version { // x86_64 supports fast class initialization checks static bool supports_fast_class_init_checks() { - return LP64_ONLY(true) NOT_LP64(false); // not implemented on x86_32 + return true; } // x86_64 supports secondary supers table constexpr static bool supports_secondary_supers_table() { - return LP64_ONLY(true) NOT_LP64(false); // not implemented on x86_32 + return true; } constexpr static bool supports_stack_watermark_barrier() { @@ -879,11 +879,7 @@ class VM_Version : public Abstract_VM_Version { // synchronize with other memory ops. so, it needs preceding // and trailing StoreStore fences. -#ifdef _LP64 static bool supports_clflush(); // Can't inline due to header file conflict -#else - static bool supports_clflush() { return ((_features & CPU_FLUSH) != 0); } -#endif // _LP64 // Note: CPU_FLUSHOPT and CPU_CLWB bits should always be zero for 32-bit static bool supports_clflushopt() { return ((_features & CPU_FLUSHOPT) != 0); } From b41e0b17490b203b19787a0d0742318fc0d03b33 Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Fri, 25 Apr 2025 07:20:25 +0000 Subject: [PATCH 025/118] 8355387: [jittester] Disable downcasts by default Reviewed-by: thartmann, chagedorn --- .../src/jdk/test/lib/jittester/ProductionParams.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java index afc526e81c7..87b5f23f58c 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,7 +121,7 @@ public static void register(OptionResolver optionResolver) { disableExternalSymbols = optionResolver.addBooleanOption("disable-external-symbols", "Don\'t use external symbols"); addExternalSymbols = optionResolver.addStringOption("add-external-symbols", "all", "Add symbols for listed classes (comma-separated list)"); disableInheritance = optionResolver.addBooleanOption("disable-inheritance", "Disable inheritance"); - disableDowncasts = optionResolver.addBooleanOption("disable-downcasts", "Disable downcasting of objects"); + disableDowncasts = optionResolver.addBooleanOption(null, "disable-downcasts", true, "Disable downcasting of objects"); disableStatic = optionResolver.addBooleanOption("disable-static", "Disable generation of static objects and functions"); disableInterfaces = optionResolver.addBooleanOption("disable-interfaces", "Disable generation of interfaces"); disableClasses = optionResolver.addBooleanOption("disable-classes", "Disable generation of classes"); From 89f9268ed7c2cb86891f23a10482cd459454bd32 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Fri, 25 Apr 2025 08:20:51 +0000 Subject: [PATCH 026/118] 8355524: Only every second line in upgradeable files is being used Reviewed-by: shade, alanb --- .../classes/jdk/tools/jlink/internal/LinkableRuntimeImage.java | 2 +- .../jlink/internal/runtimelink/upgrade_files_java.base.conf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/LinkableRuntimeImage.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/LinkableRuntimeImage.java index d564ed0bad8..30c37961829 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/LinkableRuntimeImage.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/LinkableRuntimeImage.java @@ -93,7 +93,7 @@ private static Set upgradeableFiles(String module) { // Skip comments continue; } - upgradeableFiles.add(scanner.nextLine()); + upgradeableFiles.add(line); } } catch (IOException e) { throw new AssertionError("Failure to retrieve upgradeable files for " + diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/runtimelink/upgrade_files_java.base.conf b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/runtimelink/upgrade_files_java.base.conf index df2ca809f08..fc5e7b4f328 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/runtimelink/upgrade_files_java.base.conf +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/runtimelink/upgrade_files_java.base.conf @@ -1,4 +1,4 @@ # Configuration for resource paths of files allowed to be # upgraded (in java.base) -lib/tzdb.dat lib/security/cacerts +lib/tzdb.dat From f66b9ba7bc1f426c430c5a99842685008c5a9dda Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Fri, 25 Apr 2025 10:08:37 +0000 Subject: [PATCH 027/118] 8346785: Potential infinite loop in JavadocTokenizer.ensures Reviewed-by: liach, hannesw --- .../com/sun/tools/javac/parser/JavadocTokenizer.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java index 5dcb4cc36d4..a2925c69d94 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java @@ -307,12 +307,13 @@ private void ensure(int need) { while (need > grow) { grow <<= 1; + // Handle overflow. + if (grow <= 0) { + throw new IndexOutOfBoundsException(); + } } - // Handle overflow. - if (grow < map.length) { - throw new IndexOutOfBoundsException(); - } else if (grow != map.length) { + if (grow != map.length) { map = Arrays.copyOf(map, grow); } } From e6cea4025b6743538da76f056fa831b02705f423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Fri, 25 Apr 2025 11:17:15 +0000 Subject: [PATCH 028/118] 8355475: UNCTest should use an existing UNC path Reviewed-by: dfuchs --- test/jdk/java/net/URLConnection/UNCTest.java | 37 +++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/test/jdk/java/net/URLConnection/UNCTest.java b/test/jdk/java/net/URLConnection/UNCTest.java index 653b4c96699..2fe88dde65b 100644 --- a/test/jdk/java/net/URLConnection/UNCTest.java +++ b/test/jdk/java/net/URLConnection/UNCTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,17 +25,46 @@ * @test * @bug 4401485 * @requires (os.family == "windows") + * @modules java.base/sun.net.www.protocol.file + * @library /test/lib * @summary Check that URL.openConnection() doesn't open connection to UNC - * @run main UNCTest file://jdk/LOCAL-JAVA/jdk1.4/win/README.txt */ +import jtreg.SkippedException; +import sun.net.www.protocol.file.FileURLConnection; + +import java.io.File; +import java.net.InetAddress; +import java.net.URI; import java.net.URL; import java.net.URLConnection; public class UNCTest { - public static void main(String args[]) throws Exception { - URL url = new URL( args[0] ); + public static void main(String[] args) throws Exception { + // Get the "computer name" for this host + String hostName = InetAddress.getLocalHost().getHostName(); + + // UNC path which always exists with Administrative Shares enabled + String path = "\\\\" + hostName + "\\C$\\Windows"; + + // Skip test if Administrative Shares is disabled + if (! new File(path).exists()) { + throw new SkippedException("Administrative Shares not enabled"); + } + + // File URL for the UNC path + URL url = new URI("file://" + hostName + "/C$/Windows").toURL(); + + // Should open a FileURLConnection for the UNC path URLConnection conn = url.openConnection(); + + // Sanity check that the connection is a FileURLConnection + if (! (conn instanceof FileURLConnection)) { + throw new Exception("Expected FileURLConnection, instead got " + + conn.getClass().getName()); + } + + // Verify that the connection is not in an already connected state conn.setRequestProperty( "User-Agent", "Java" ); } } From a2f9c248447d2840d191366cead1ba474ed9a15a Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Fri, 25 Apr 2025 11:31:10 +0000 Subject: [PATCH 029/118] 8354327: Rewrite runtime/LoadClass/LoadClassNegative.java Reviewed-by: coleenp, lmesnik --- .../jtreg/runtime/LoadClass/LoadClassNegative.java | 13 ++++++++++--- test/hotspot/jtreg/runtime/LoadClass/dummy.jar | 0 2 files changed, 10 insertions(+), 3 deletions(-) delete mode 100644 test/hotspot/jtreg/runtime/LoadClass/dummy.jar diff --git a/test/hotspot/jtreg/runtime/LoadClass/LoadClassNegative.java b/test/hotspot/jtreg/runtime/LoadClass/LoadClassNegative.java index 94c2bde6e76..a9ddd5268c5 100644 --- a/test/hotspot/jtreg/runtime/LoadClass/LoadClassNegative.java +++ b/test/hotspot/jtreg/runtime/LoadClass/LoadClassNegative.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,8 +40,15 @@ public class LoadClassNegative { public static void main(String args[]) throws Exception { - String bootCP = "-Xbootclasspath/a:" + System.getProperty("test.src") - + File.separator + "dummy.jar"; + + // Create an empty file in the scratch directory + final String filename = "empty.jar"; + File emptyJar = new File(filename); + emptyJar.createNewFile(); + + // Explicitly tell to use it for class loading + String bootCP = "-Xbootclasspath/a:" + emptyJar.getAbsolutePath(); + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( bootCP, "TestForName"); diff --git a/test/hotspot/jtreg/runtime/LoadClass/dummy.jar b/test/hotspot/jtreg/runtime/LoadClass/dummy.jar deleted file mode 100644 index e69de29bb2d..00000000000 From 5c067232bf21aaca2b7addd2a862e15a8696ffb8 Mon Sep 17 00:00:00 2001 From: Anjian-Wen Date: Fri, 25 Apr 2025 12:50:12 +0000 Subject: [PATCH 030/118] 8355074: RISC-V: C2: Support Vector-Scalar version of Zvbb Vector And-Not instruction Reviewed-by: fjiang, fyang --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 1 + src/hotspot/cpu/riscv/riscv_v.ad | 64 +++++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 20 ++++++ .../AllBitsSetVectorMatchRuleTest.java | 62 ++++++++++++++++++ 4 files changed, 147 insertions(+) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index e036cb6b1ec..4773043e1ba 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2323,6 +2323,7 @@ enum Nf { } // Vector Bit-manipulation used in Cryptography (Zvbb) Extension + INSN(vandn_vx, 0b1010111, 0b100, 0b000001); INSN(vrol_vx, 0b1010111, 0b100, 0b010101); INSN(vror_vx, 0b1010111, 0b100, 0b010100); diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 6fea439954c..7df3c857a4d 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -1187,6 +1187,70 @@ instruct vand_notL_masked(vReg dst_src1, vReg src2, immL_M1 m1, vRegMask_V0 v0) ins_pipe(pipe_slow); %} +instruct vand_notI_vx(vReg dst, vReg src1, iRegIorL2I src2, immI_M1 m1) %{ + predicate(UseZvbb); + predicate(Matcher::vector_element_basic_type(n) == T_INT || + Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT); + match(Set dst (AndV src1 (Replicate (XorI src2 m1)))); + format %{ "vand_notI_vx $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notL_vx(vReg dst, vReg src1, iRegL src2, immL_M1 m1) %{ + predicate(UseZvbb); + predicate(Matcher::vector_element_basic_type(n) == T_LONG); + match(Set dst (AndV src1 (Replicate (XorL src2 m1)))); + format %{ "vand_notL_vx $dst, $src1, $src2" %} + ins_encode %{ + __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notI_vx_masked(vReg dst_src1, iRegIorL2I src2, immI_M1 m1, vRegMask_V0 v0) %{ + predicate(UseZvbb); + predicate(Matcher::vector_element_basic_type(n) == T_INT || + Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT); + match(Set dst_src1 (AndV (Binary dst_src1 (Replicate (XorI src2 m1))) v0)); + format %{ "vand_notI_vx_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($dst_src1$$reg), + as_Register($src2$$reg), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notL_vx_masked(vReg dst_src1, iRegL src2, immL_M1 m1, vRegMask_V0 v0) %{ + predicate(UseZvbb); + predicate(Matcher::vector_element_basic_type(n) == T_LONG); + match(Set dst_src1 (AndV (Binary dst_src1 (Replicate (XorL src2 m1))) v0)); + format %{ "vand_notL_vx_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($dst_src1$$reg), + as_Register($src2$$reg), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + // ------------------------------ Vector not ----------------------------------- // vector not diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 0b224523561..5dabcf0f828 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2136,6 +2136,26 @@ public class IRNode { machOnlyNameRegex(VAND_NOT_L_MASKED, "vand_notL_masked"); } + public static final String RISCV_VAND_NOTI_VX = PREFIX + "RISCV_VAND_NOTI_VX" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VAND_NOTI_VX, "vand_notI_vx"); + } + + public static final String RISCV_VAND_NOTL_VX = PREFIX + "RISCV_VAND_NOTL_VX" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VAND_NOTL_VX, "vand_notL_vx"); + } + + public static final String RISCV_VAND_NOTI_VX_MASKED = PREFIX + "RISCV_VAND_NOTI_VX_MASKED" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VAND_NOTI_VX_MASKED, "vand_notI_vx_masked"); + } + + public static final String RISCV_VAND_NOTL_VX_MASKED = PREFIX + "RISCV_VAND_NOTL_VX_MASKED" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VAND_NOTL_VX_MASKED, "vand_notL_vx_masked"); + } + public static final String VECTOR_BLEND_B = VECTOR_PREFIX + "VECTOR_BLEND_B" + POSTFIX; static { vectorNode(VECTOR_BLEND_B, "VectorBlend", TYPE_BYTE); diff --git a/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java b/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java index f33dd24e726..bb88f60dd21 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java @@ -154,6 +154,68 @@ public static void testVectorVAndNotLMasked() { } } + @Test + @Warmup(10000) + @IR(counts = { IRNode.RISCV_VAND_NOTI_VX, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testAllBitsSetVectorRegI() { + IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); + int bs = ib[0]; + av.not().lanewise(VectorOperators.AND_NOT, bs).intoArray(ir, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + Asserts.assertEquals((~ia[i]) & (~bs), ir[i]); + } + } + + @Test + @Warmup(10000) + @IR(counts = { IRNode.RISCV_VAND_NOTL_VX, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testAllBitsSetVectorRegL() { + LongVector av = LongVector.fromArray(L_SPECIES, la, 0); + long bs = lb[0]; + av.not().lanewise(VectorOperators.AND_NOT, bs).intoArray(lr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + Asserts.assertEquals((~la[i]) & (~bs), lr[i]); + } + } + + @Test + @Warmup(10000) + @IR(counts = { IRNode.RISCV_VAND_NOTI_VX_MASKED, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testAllBitsSetVectorRegIMask() { + VectorMask avm = VectorMask.fromArray(I_SPECIES, ma, 0); + IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); + int bs = ib[0]; + av.not().lanewise(VectorOperators.AND_NOT, bs, avm).intoArray(ir, 0); + + // Verify results + for (int i = 0; i < I_SPECIES.length(); i++) { + if (ma[i] == true) { + Asserts.assertEquals((~ia[i]) & (~bs), ir[i]); + } + } + } + + @Test + @Warmup(10000) + @IR(counts = { IRNode.RISCV_VAND_NOTL_VX_MASKED, " >= 1" }, applyIfPlatform = {"riscv64", "true"}) + public static void testAllBitsSetVectorRegLMask() { + VectorMask avm = VectorMask.fromArray(L_SPECIES, ma, 0); + LongVector av = LongVector.fromArray(L_SPECIES, la, 0); + long bs = lb[0]; + av.not().lanewise(VectorOperators.AND_NOT, bs, avm).intoArray(lr, 0); + + // Verify results + for (int i = 0; i < L_SPECIES.length(); i++) { + if (ma[i] == true) { + Asserts.assertEquals((~la[i]) & (~bs), lr[i]); + } + } + } + @Test @Warmup(10000) @IR(counts = { IRNode.VAND_NOT_L, " >= 1" }, applyIfPlatform = {"aarch64", "true"}, applyIf = {"UseSVE", "0"}) From 597bcc695347544b9feffc5280741b1e9e1715f7 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Fri, 25 Apr 2025 16:12:35 +0000 Subject: [PATCH 031/118] 8352003: Support --add-opens with -XX:+AOTClassLinking Co-authored-by: Alan Bateman Reviewed-by: iklam, alanb, matsaave --- src/hotspot/share/classfile/modules.cpp | 5 +- src/hotspot/share/runtime/arguments.cpp | 2 +- .../share/classes/java/lang/Module.java | 90 +++++----- .../share/classes/java/lang/System.java | 3 - .../jdk/internal/access/JavaLangAccess.java | 5 - .../jdk/internal/module/ModuleBootstrap.java | 11 +- .../cds/appcds/jigsaw/ExactOptionMatch.java | 4 + .../jigsaw/addopens/AddopensOption.java | 156 ++++++++++++++++++ .../appcds/jigsaw/modulepath/AddOpens.java | 64 ++++--- 9 files changed, 250 insertions(+), 90 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addopens/AddopensOption.java diff --git a/src/hotspot/share/classfile/modules.cpp b/src/hotspot/share/classfile/modules.cpp index 3f2ff90ccab..05be2df52af 100644 --- a/src/hotspot/share/classfile/modules.cpp +++ b/src/hotspot/share/classfile/modules.cpp @@ -580,13 +580,14 @@ class Modules::ArchivedProperty { }; Modules::ArchivedProperty Modules::_archived_props[] = { - // numbered + // non-numbered {"jdk.module.main", false}, - // non-numbered + // numbered {"jdk.module.addexports", true}, // --add-exports {"jdk.module.addmods", true}, // --add-modules {"jdk.module.enable.native.access", true}, // --enable-native-access + {"jdk.module.addopens", true}, // --add-opens }; constexpr size_t Modules::num_archived_props() { diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index b3e0600df34..d0bba58b508 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -332,7 +332,6 @@ bool Arguments::internal_module_property_helper(const char* property, bool check if (strncmp(property, MODULE_PROPERTY_PREFIX, MODULE_PROPERTY_PREFIX_LEN) == 0) { const char* property_suffix = property + MODULE_PROPERTY_PREFIX_LEN; if (matches_property_suffix(property_suffix, ADDREADS, ADDREADS_LEN) || - matches_property_suffix(property_suffix, ADDOPENS, ADDOPENS_LEN) || matches_property_suffix(property_suffix, PATCH, PATCH_LEN) || matches_property_suffix(property_suffix, LIMITMODS, LIMITMODS_LEN) || matches_property_suffix(property_suffix, UPGRADE_PATH, UPGRADE_PATH_LEN) || @@ -343,6 +342,7 @@ bool Arguments::internal_module_property_helper(const char* property, bool check if (!check_for_cds) { // CDS notes: these properties are supported by CDS archived full module graph. if (matches_property_suffix(property_suffix, ADDEXPORTS, ADDEXPORTS_LEN) || + matches_property_suffix(property_suffix, ADDOPENS, ADDOPENS_LEN) || matches_property_suffix(property_suffix, PATH, PATH_LEN) || matches_property_suffix(property_suffix, ADDMODS, ADDMODS_LEN) || matches_property_suffix(property_suffix, ENABLE_NATIVE_ACCESS, ENABLE_NATIVE_ACCESS_LEN)) { diff --git a/src/java.base/share/classes/java/lang/Module.java b/src/java.base/share/classes/java/lang/Module.java index dcc92d012de..065e1ac4620 100644 --- a/src/java.base/share/classes/java/lang/Module.java +++ b/src/java.base/share/classes/java/lang/Module.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,6 @@ import java.net.URI; import java.net.URL; import java.security.CodeSource; -import java.security.ProtectionDomain; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -688,7 +687,6 @@ public boolean isOpen(String pn) { return implIsExportedOrOpen(pn, EVERYONE_MODULE, /*open*/true); } - /** * Returns {@code true} if this module exports or opens the given package * to the given module. If the other module is {@code EVERYONE_MODULE} then @@ -707,12 +705,12 @@ private boolean implIsExportedOrOpen(String pn, Module other, boolean open) { if (descriptor.isOpen() || descriptor.isAutomatic()) return descriptor.packages().contains(pn); - // exported/opened via module declaration/descriptor - if (isStaticallyExportedOrOpen(pn, other, open)) + // exported/opened via module declaration/descriptor or CLI options + if (isExplicitlyExportedOrOpened(pn, other, open)) return true; // exported via addExports/addOpens - if (isReflectivelyExportedOrOpen(pn, other, open)) + if (isReflectivelyExportedOrOpened(pn, other, open)) return true; // not exported or open to other @@ -723,7 +721,7 @@ private boolean implIsExportedOrOpen(String pn, Module other, boolean open) { * Returns {@code true} if this module exports or opens a package to * the given module via its module declaration or CLI options. */ - private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) { + private boolean isExplicitlyExportedOrOpened(String pn, Module other, boolean open) { // test if package is open to everyone or Map> openPackages = this.openPackages; if (openPackages != null && allows(openPackages.get(pn), other)) { @@ -764,7 +762,7 @@ private boolean allows(Set targets, Module module) { * Returns {@code true} if this module reflectively exports or opens the * given package to the given module. */ - private boolean isReflectivelyExportedOrOpen(String pn, Module other, boolean open) { + private boolean isReflectivelyExportedOrOpened(String pn, Module other, boolean open) { // exported or open to all modules Map exports = ReflectionData.exports.get(this, EVERYONE_MODULE); if (exports != null) { @@ -809,7 +807,7 @@ private boolean isReflectivelyExportedOrOpen(String pn, Module other, boolean op * given package to the given module. */ boolean isReflectivelyExported(String pn, Module other) { - return isReflectivelyExportedOrOpen(pn, other, false); + return isReflectivelyExportedOrOpened(pn, other, false); } /** @@ -817,7 +815,7 @@ boolean isReflectivelyExported(String pn, Module other) { * given package to the given module. */ boolean isReflectivelyOpened(String pn, Module other) { - return isReflectivelyExportedOrOpen(pn, other, true); + return isReflectivelyExportedOrOpened(pn, other, true); } @@ -1033,50 +1031,38 @@ private void implAddExportsOrOpens(String pn, } } - // add package name to exports if absent - Map map = ReflectionData.exports - .computeIfAbsent(this, other, - (m1, m2) -> new ConcurrentHashMap<>()); - if (open) { - map.put(pn, Boolean.TRUE); // may need to promote from FALSE to TRUE - } else { - map.putIfAbsent(pn, Boolean.FALSE); - } - } - - /** - * Updates a module to open all packages in the given sets to all unnamed - * modules. - * - * @apiNote Used during startup to open packages for illegal access. - */ - void implAddOpensToAllUnnamed(Set concealedPkgs, Set exportedPkgs) { - if (jdk.internal.misc.VM.isModuleSystemInited()) { - throw new IllegalStateException("Module system already initialized"); - } - - // replace this module's openPackages map with a new map that opens - // the packages to all unnamed modules. - Map> openPackages = this.openPackages; - if (openPackages == null) { - openPackages = HashMap.newHashMap(concealedPkgs.size() + exportedPkgs.size()); + if (VM.isBooted()) { + // add package name to ReflectionData.exports if absent + Map map = ReflectionData.exports + .computeIfAbsent(this, other, + (m1, m2) -> new ConcurrentHashMap<>()); + if (open) { + map.put(pn, Boolean.TRUE); // may need to promote from FALSE to TRUE + } else { + map.putIfAbsent(pn, Boolean.FALSE); + } } else { - openPackages = new HashMap<>(openPackages); - } - implAddOpensToAllUnnamed(concealedPkgs, openPackages); - implAddOpensToAllUnnamed(exportedPkgs, openPackages); - this.openPackages = openPackages; - } - - private void implAddOpensToAllUnnamed(Set pkgs, Map> openPackages) { - for (String pn : pkgs) { - Set prev = openPackages.putIfAbsent(pn, ALL_UNNAMED_MODULE_SET); - if (prev != null) { - prev.add(ALL_UNNAMED_MODULE); + // export/open packages during startup (--add-exports and --add-opens) + Map> packageToTargets = (open) ? openPackages : exportedPackages; + if (packageToTargets != null) { + // copy existing map + packageToTargets = new HashMap<>(packageToTargets); + packageToTargets.compute(pn, (_, values) -> { + var targets = new HashSet(); + if (values != null) { + targets.addAll(values); + } + targets.add(other); + return targets; + }); + } else { + packageToTargets = Map.of(pn, Set.of(other)); + } + if (open) { + this.openPackages = packageToTargets; + } else { + this.exportedPackages = packageToTargets; } - - // update VM to export the package - addExportsToAllUnnamed0(this, pn); } } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 903f6e34e2e..f9b4698854d 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2059,9 +2059,6 @@ public void addOpens(Module m, String pn, Module other) { public void addOpensToAllUnnamed(Module m, String pn) { m.implAddOpensToAllUnnamed(pn); } - public void addOpensToAllUnnamed(Module m, Set concealedPackages, Set exportedPackages) { - m.implAddOpensToAllUnnamed(concealedPackages, exportedPackages); - } public void addUses(Module m, Class service) { m.implAddUses(service); } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index 8edeb731cee..9e11bd7586f 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -230,11 +230,6 @@ public interface JavaLangAccess { */ void addOpensToAllUnnamed(Module m, String pkg); - /** - * Updates module m to open all packages in the given sets. - */ - void addOpensToAllUnnamed(Module m, Set concealedPkgs, Set exportedPkgs); - /** * Updates module m to use a service. */ diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java index 0a9044178a4..39c52f25514 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java @@ -142,8 +142,7 @@ private static boolean canUseArchivedBootLayer() { return getProperty("jdk.module.upgrade.path") == null && getProperty("jdk.module.patch.0") == null && // --patch-module getProperty("jdk.module.limitmods") == null && // --limit-modules - getProperty("jdk.module.addreads.0") == null && // --add-reads - getProperty("jdk.module.addopens.0") == null; // --add-opens + getProperty("jdk.module.addreads.0") == null; // --add-reads } /** @@ -452,7 +451,7 @@ private static ModuleLayer boot2() { // --add-reads, --add-exports/--add-opens addExtraReads(bootLayer); - boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer); + addExtraExportsAndOpens(bootLayer); // add enable native access addEnableNativeAccess(bootLayer); @@ -722,15 +721,13 @@ private static void addExtraReads(ModuleLayer bootLayer) { * Process the --add-exports and --add-opens options to export/open * additional packages specified on the command-line. */ - private static boolean addExtraExportsAndOpens(ModuleLayer bootLayer) { - boolean extraExportsOrOpens = false; + private static void addExtraExportsAndOpens(ModuleLayer bootLayer) { // --add-exports String prefix = "jdk.module.addexports."; Map> extraExports = decode(prefix); if (!extraExports.isEmpty()) { addExtraExportsOrOpens(bootLayer, extraExports, false); - extraExportsOrOpens = true; } @@ -739,10 +736,8 @@ private static boolean addExtraExportsAndOpens(ModuleLayer bootLayer) { Map> extraOpens = decode(prefix); if (!extraOpens.isEmpty()) { addExtraExportsOrOpens(bootLayer, extraOpens, true); - extraExportsOrOpens = true; } - return extraExportsOrOpens; } private static void addExtraExportsOrOpens(ModuleLayer bootLayer, diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/ExactOptionMatch.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/ExactOptionMatch.java index e3fb6094c1d..dd8f186af80 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/ExactOptionMatch.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/ExactOptionMatch.java @@ -39,6 +39,10 @@ public class ExactOptionMatch { record Option(String cmdLine, String property, String valueA, String valueB) {} static Option[] allOptions = new Option[] { + new Option("--add-opens", + "jdk.module.addopens", + "java.base/java.util.concurrent.regex=ALL-UNNAMED", + "java.base/sun.security.x509=ALL-UNNAMED"), new Option("--add-exports", "jdk.module.addexports", "java.base/jdk.internal.misc=ALL-UNNAMED", diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addopens/AddopensOption.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addopens/AddopensOption.java new file mode 100644 index 00000000000..81b24d15f9e --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addopens/AddopensOption.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8352003 + * @summary Test handling of the --add-opens option. + * @requires vm.cds.write.archived.java.heap + * @requires vm.flagless + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @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 AddopensOption + */ + +import jdk.test.lib.process.OutputAnalyzer; + +public class AddopensOption { + + public static void main(String[] args) throws Exception { + final String moduleOption = "jdk.httpserver/sun.net.httpserver.simpleserver.Main"; + final String addOpensNio = "java.base/java.nio=ALL-UNNAMED"; + final String addOpensTimeFormat = "java.base/java.time.format=ALL-UNNAMED"; + final String loggingOption = "-Xlog:cds=debug,cds+module=debug,cds+heap=info,module=trace"; + final String versionPattern = "java.[0-9][0-9].*"; + final String subgraphCannotBeUsed = "subgraph jdk.internal.module.ArchivedBootLayer cannot be used because full module graph is disabled"; + final String warningIncubator = "WARNING: Using incubator modules: jdk.incubator.vector"; + String archiveName = TestCommon.getNewArchiveName("addopens-option"); + TestCommon.setCurrentArchiveName(archiveName); + + // dump a base archive with --add-opens jdk.java.base/java.time.format -m jdk.httpserver + OutputAnalyzer oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "--add-opens", addOpensTimeFormat, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0); + + // same modules specified during runtime + oa = TestCommon.execCommon( + loggingOption, + "--add-opens", addOpensTimeFormat, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + // version of the jdk.httpserver module, e.g. java 22-ea + .shouldMatch(versionPattern) + .shouldMatch("cds,module.*Restored from archive: entry.0x.*name jdk.httpserver"); + + // different --add-opens specified during runtime + oa = TestCommon.execCommon( + loggingOption, + "--add-opens", addOpensNio, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + .shouldContain("Mismatched values for property jdk.module.addopens") + .shouldContain("runtime java.base/java.nio=ALL-UNNAMED dump time java.base/java.time.format=ALL-UNNAMED") + .shouldContain(subgraphCannotBeUsed); + + // no module specified during runtime + oa = TestCommon.execCommon( + loggingOption, + "-version"); + oa.shouldHaveExitValue(0) + .shouldContain("jdk.httpserver specified during dump time but not during runtime") + .shouldContain(subgraphCannotBeUsed); + + // dump an archive without the --add-opens option + archiveName = TestCommon.getNewArchiveName("no-addopens-option"); + TestCommon.setCurrentArchiveName(archiveName); + oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0); + + // run with --add-opens option + oa = TestCommon.execCommon( + loggingOption, + "--add-opens", addOpensTimeFormat, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + .shouldContain("java.base/java.time.format=ALL-UNNAMED specified during runtime but not during dump time") + // version of the jdk.httpserver module, e.g. java 22-ea + .shouldMatch(versionPattern) + .shouldContain(subgraphCannotBeUsed); + + // dump an archive with -add-opens java.base/java.nio=ALL-UNNAMED + archiveName = TestCommon.getNewArchiveName("addopens-java-nio"); + TestCommon.setCurrentArchiveName(archiveName); + oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "--add-opens", addOpensNio, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + .shouldContain("Full module graph = enabled"); + + // run with the same --add-opens + oa = TestCommon.execCommon( + loggingOption, + "--add-opens", addOpensNio, + "-m", moduleOption, + "-version"); + oa.shouldContain("optimized module handling: enabled") + .shouldHaveExitValue(0); + + // dump an archive with multiple --add-modules args + archiveName = TestCommon.getNewArchiveName("muti-addopens"); + TestCommon.setCurrentArchiveName(archiveName); + oa = TestCommon.dumpBaseArchive( + archiveName, + loggingOption, + "--add-opens", addOpensNio, + "--add-opens", addOpensTimeFormat, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0); + + // run with the same multiple --add-modules args with a duplicate --add-opens entry + oa = TestCommon.execCommon( + loggingOption, + "--add-opens", addOpensTimeFormat, + "--add-opens", addOpensNio, + "--add-opens", addOpensTimeFormat, + "-m", moduleOption, + "-version"); + oa.shouldHaveExitValue(0) + .shouldMatch("cds,module.*Restored from archive: entry.0x.*name jdk.httpserver"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/AddOpens.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/AddOpens.java index fbb9b723a90..b181d23f64c 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/AddOpens.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/AddOpens.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,6 +57,15 @@ public class AddOpens { private static Path moduleDir2 = null; private static Path destJar = null; + private static String addOpensArg = "java.base/java.lang=" + TEST_MODULE1; + private static String addOpensAllUnnamed = "java.base/java.lang=ALL-UNNAMED"; + private static String extraOpts[][] = + {{"-Xlog:cds", "-Xlog:cds"}, + {"--add-opens", addOpensArg}}; + private static String expectedOutput[] = + { "[class,load] com.simple.Main source: shared objects file", + "method.setAccessible succeeded!"}; + public static void buildTestModule() throws Exception { // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** @@ -79,28 +88,45 @@ public static void main(String... args) throws Exception { // compile the modules and create the modular jar files buildTestModule(); String appClasses[] = {MAIN_CLASS}; - // create an archive with both -cp and --module-path in the command line. - // Only the class in the modular jar in the --module-path will be archived; - // the class in the modular jar in the -cp won't be archived. - OutputAnalyzer output = TestCommon.createArchive( - destJar.toString(), appClasses, - "--module-path", moduleDir.toString(), - "-m", TEST_MODULE1); + OutputAnalyzer output; + + for (int i = 0; i < 2; i++) { + // create an archive with both -cp and --module-path, and with the + // --add-opens option if i == 1, in the command line. + // Only the class in the modular jar in the --module-path will be archived; + // the class in the modular jar in the -cp won't be archived. + output = TestCommon.createArchive( + destJar.toString(), appClasses, + extraOpts[i][0], extraOpts[i][1], + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE1); + TestCommon.checkDump(output); + + // run with the archive using the same command line as in dump time + // plus the "--add-opens java.base/java.lang=com.simple" option. + // The main class should be loaded from the archive. + // The setaccessible(true) on the ClassLoader.defineClass method should + // be successful. + TestCommon.run( "-Xlog:class+load=trace", + "-cp", destJar.toString(), + "--add-opens", addOpensArg, + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE1, "with_add_opens") + .assertNormalExit(expectedOutput[0], expectedOutput[1]); + } + + // Test --add-opens to ALL-UNNAMED modules + output = TestCommon.createArchive( + destJar.toString(), appClasses, + "--add-opens", addOpensAllUnnamed, + MAIN_CLASS); TestCommon.checkDump(output); - // run with the archive using the same command line as in dump time - // plus the "--add-opens java.base/java.lang=com.simple" option. - // The main class should be loaded from the archive. - // The setaccessible(true) on the ClassLoader.defineClass method should - // be successful. TestCommon.run( "-Xlog:class+load=trace", "-cp", destJar.toString(), - "--add-opens", "java.base/java.lang=" + TEST_MODULE1, - "--module-path", moduleDir.toString(), - "-m", TEST_MODULE1, "with_add_opens") - .assertNormalExit( - "[class,load] com.simple.Main source: shared objects file", - "method.setAccessible succeeded!"); + "--add-opens", addOpensAllUnnamed, + MAIN_CLASS, "with_add_opens") + .assertNormalExit(expectedOutput[0], expectedOutput[1]); } } From 77f5a24648758cb1adc74056ca58f880af4a8e84 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 25 Apr 2025 16:30:26 +0000 Subject: [PATCH 032/118] 8355214: nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter001.java should use JDIBase superclass Reviewed-by: lmesnik, sspitsyn --- .../addThreadFilter/addthreadfilter002.java | 164 +----------------- .../nsk/share/jdi/EventFilters.java | 5 +- .../vmTestbase/nsk/share/jdi/JDIBase.java | 3 + 3 files changed, 10 insertions(+), 162 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter002.java index 9b040a17eb1..bc0d7ac70c4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,20 +75,7 @@ *
*/ -public class addthreadfilter002 { - - //----------------------------------------------------- templete section - static final int PASSED = 0; - static final int FAILED = 2; - static final int PASS_BASE = 95; - - //----------------------------------------------------- templete parameters - static final String - sHeader1 = "\n==> nsk/jdi/ThreadStartRequest/addThreadFilter/addthreadfilter002 ", - sHeader2 = "--> debugger: ", - sHeader3 = "##> debugger: "; - - //----------------------------------------------------- main method +public class addthreadfilter002 extends JDIBase { public static void main (String argv[]) { @@ -109,43 +96,12 @@ public static int run (String argv[], PrintStream out) { return exitCode; } - //-------------------------------------------------- log procedures - - private static Log logHandler; - - private static void log1(String message) { - logHandler.display(sHeader1 + message); - } - private static void log2(String message) { - logHandler.display(sHeader2 + message); - } - private static void log3(String message) { - logHandler.complain(sHeader3 + message); - } - // ************************************************ test parameters private String debuggeeName = "nsk.jdi.ThreadStartRequest.addThreadFilter.addthreadfilter002a"; //====================================================== test program - //------------------------------------------------------ common section - - static Debugee debuggee; - static ArgumentHandler argsHandler; - - static int waitTime; - - static VirtualMachine vm = null; - static EventRequestManager eventRManager = null; - static EventQueue eventQueue = null; - static EventSet eventSet = null; - static EventIterator eventIterator = null; - - static ReferenceType debuggeeClass = null; - - static int testExitCode = PASSED; - //------------------------------------------------------ methods @@ -287,16 +243,7 @@ private void testRun() log2(" received: ClassPrepareEvent for debuggeeClass"); - String bPointMethod = "methodForCommunication"; - String lineForComm = "lineForComm"; - BreakpointRequest bpRequest; - - ThreadReference mainThread = debuggee.threadByNameOrThrow("main"); - - bpRequest = settingBreakpoint(mainThread, - debuggeeClass, - bPointMethod, lineForComm, "zero"); - bpRequest.enable(); + setupBreakpointForCommunication(debuggeeClass); //------------------------------------------------------ testing section @@ -307,6 +254,7 @@ private void testRun() vm.resume(); breakpointForCommunication(); + ThreadReference mainThread = bpEvent.thread(); // bpEvent saved by breakpointForCommunication() int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); @@ -378,108 +326,4 @@ private void testRun() return; } - /* - * private BreakpointRequest settingBreakpoint(ThreadReference, ReferenceType, - * String, String, String) - * - * It sets up a breakpoint at given line number within a given method in a given class - * for a given thread. - * - * Return value: BreakpointRequest object in case of success - * - * JDITestRuntimeException in case of an Exception thrown within the method - */ - - private BreakpointRequest settingBreakpoint ( ThreadReference thread, - ReferenceType testedClass, - String methodName, - String bpLine, - String property) - throws JDITestRuntimeException { - - log2("......setting up a breakpoint:"); - log2(" thread: " + thread + "; class: " + testedClass + - "; method: " + methodName + "; line: " + bpLine); - - List alllineLocations = null; - Location lineLocation = null; - BreakpointRequest breakpRequest = null; - - try { - Method method = (Method) testedClass.methodsByName(methodName).get(0); - - alllineLocations = method.allLineLocations(); - - int n = - ( (IntegerValue) testedClass.getValue(testedClass.fieldByName(bpLine) ) ).value(); - if (n > alllineLocations.size()) { - log3("ERROR: TEST_ERROR_IN_settingBreakpoint(): number is out of bound of method's lines"); - } else { - lineLocation = (Location) alllineLocations.get(n); - try { - breakpRequest = eventRManager.createBreakpointRequest(lineLocation); - breakpRequest.putProperty("number", property); - breakpRequest.addThreadFilter(thread); - breakpRequest.setSuspendPolicy( EventRequest.SUSPEND_EVENT_THREAD); - } catch ( Exception e1 ) { - log3("ERROR: inner Exception within settingBreakpoint() : " + e1); - breakpRequest = null; - } - } - } catch ( Exception e2 ) { - log3("ERROR: ATTENTION: outer Exception within settingBreakpoint() : " + e2); - breakpRequest = null; - } - - if (breakpRequest == null) { - log2(" A BREAKPOINT HAS NOT BEEN SET UP"); - throw new JDITestRuntimeException("**FAILURE to set up a breakpoint**"); - } - - log2(" a breakpoint has been set up"); - return breakpRequest; - } - - - private void getEventSet() - throws JDITestRuntimeException { - try { -// log2(" eventSet = eventQueue.remove(waitTime);"); - eventSet = eventQueue.remove(waitTime); - if (eventSet == null) { - throw new JDITestRuntimeException("** TIMEOUT while waiting for event **"); - } -// log2(" eventIterator = eventSet.eventIterator;"); - eventIterator = eventSet.eventIterator(); - } catch ( Exception e ) { - throw new JDITestRuntimeException("** EXCEPTION while waiting for event ** : " + e); - } - } - - - private void breakpointForCommunication() - throws JDITestRuntimeException { - - log2("breakpointForCommunication"); - while (true) { - getEventSet(); - while (eventIterator.hasNext()) { - Event event = eventIterator.nextEvent(); - if (event instanceof BreakpointEvent) { - return; - } else if (event instanceof ThreadStartEvent) { - // It might be the case that while the thread start request was enabled - // some threads not related to the test ( e.g. JVMCI threads) were started - // and generated thread start events. We ignore these thread start events - // and keep waiting for a breakpoint event. - ThreadStartEvent tse = (ThreadStartEvent) event; - log2("ThreadStartEvent is received while waiting for a breakpoint" + - " event, thread: : " + tse.thread().name()); - continue; - } - throw new JDITestRuntimeException("** event IS NOT a breakpoint or a thread start **"); - } - } - } - } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventFilters.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventFilters.java index be4157f394f..c3d3ae5ad9f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventFilters.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventFilters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -341,11 +341,12 @@ public static boolean filtered(Event event) { "VirtualThread-unparker", "Cleaner-", "Common-Cleaner", + "CompilerThread", "FinalizerThread", "ForkJoinPool" }; for (String s : knownThreads) { - if (tname.startsWith(s)) { + if (tname.indexOf(s) != -1) { return true; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java index ac99b121651..88b1de413dd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java @@ -239,6 +239,9 @@ protected void breakpointForCommunication() throws JDITestRuntimeException { if (EventFilters.filtered(event)) { // We filter out spurious ThreadStartEvents + ThreadStartEvent tse = (ThreadStartEvent) event; + log2("ThreadStartEvent is received while waiting for a breakpoint" + + " event, thread: : " + tse.thread().name()); continue; } From 15f42e348d4068bd90dd75b270a372353fe0ed07 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Fri, 25 Apr 2025 16:32:42 +0000 Subject: [PATCH 033/118] 8350703: Add standard system property stdin.encoding Reviewed-by: naoto, alanb --- .../share/classes/java/lang/System.java | 41 ++++++++++++------- .../jdk/internal/util/SystemProps.java | 12 ++++-- src/java.base/share/native/libjava/System.c | 1 + .../share/native/libjava/java_props.h | 1 + .../unix/native/libjava/java_props_md.c | 3 ++ .../windows/native/libjava/java_props_md.c | 19 +++++---- test/jdk/java/lang/System/PropertyTest.java | 1 + 7 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index f9b4698854d..dc969c72536 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -116,15 +116,23 @@ private System() { /** * The "standard" input stream. This stream is already - * open and ready to supply input data. Typically this stream + * open and ready to supply input data. This stream * corresponds to keyboard input or another input source specified by - * the host environment or user. In case this stream is wrapped - * in a {@link java.io.InputStreamReader}, {@link Console#charset()} - * should be used for the charset, or consider using - * {@link Console#reader()}. + * the host environment or user. Applications should use the encoding + * specified by the {@link ##stdin.encoding stdin.encoding} property + * to convert input bytes to character data. * - * @see Console#charset() - * @see Console#reader() + * @apiNote + * The typical approach to read character data is to wrap {@code System.in} + * within an {@link java.io.InputStreamReader InputStreamReader} or other object + * that handles character encoding. After this is done, subsequent reading should + * use only the wrapper object; operating directly on {@code System.in} results + * in unspecified behavior. + *

+ * For handling interactive input, consider using {@link Console}. + * + * @see Console + * @see ##stdin.encoding stdin.encoding */ public static final InputStream in = null; @@ -575,17 +583,22 @@ public static native void arraycopy(Object src, int srcPos, * {@systemProperty user.dir} * User's current working directory * {@systemProperty native.encoding} - * Character encoding name derived from the host environment and/or - * the user's settings. Setting this system property has no effect. + * Character encoding name derived from the host environment and + * the user's settings. Setting this system property on the command line + * has no effect. + * {@systemProperty stdin.encoding} + * Character encoding name for {@link System#in System.in}. + * The Java runtime can be started with the system property set to {@code UTF-8}. + * Starting it with the property set to another value results in unspecified behavior. * {@systemProperty stdout.encoding} * Character encoding name for {@link System#out System.out} and * {@link System#console() System.console()}. - * The Java runtime can be started with the system property set to {@code UTF-8}, - * starting it with the property set to another value leads to undefined behavior. + * The Java runtime can be started with the system property set to {@code UTF-8}. + * Starting it with the property set to another value results in unspecified behavior. * {@systemProperty stderr.encoding} * Character encoding name for {@link System#err System.err}. - * The Java runtime can be started with the system property set to {@code UTF-8}, - * starting it with the property set to another value leads to undefined behavior. + * The Java runtime can be started with the system property set to {@code UTF-8}. + * Starting it with the property set to another value results in unspecified behavior. * * *

@@ -639,7 +652,7 @@ public static native void arraycopy(Object src, int srcPos, * the value {@code COMPAT} then the value is replaced with the * value of the {@code native.encoding} property during startup. * Setting the property to a value other than {@code UTF-8} or - * {@code COMPAT} leads to unspecified behavior. + * {@code COMPAT} results in unspecified behavior. * * * diff --git a/src/java.base/share/classes/jdk/internal/util/SystemProps.java b/src/java.base/share/classes/jdk/internal/util/SystemProps.java index 26110a1dab3..5760f04831e 100644 --- a/src/java.base/share/classes/jdk/internal/util/SystemProps.java +++ b/src/java.base/share/classes/jdk/internal/util/SystemProps.java @@ -88,9 +88,12 @@ public static Map initProperties() { put(props, "file.encoding", nativeEncoding); } - // "stdout/err.encoding", prepared for System.out/err. For compatibility - // purposes, substitute them with "sun.*" if they don't exist. If "sun.*" aren't - // available either, fall back to "native.encoding". + // Encoding properties for stdin, stdout, and stderr. For stdout and stderr, + // check "sun.stdout.encoding" and "sun.stderr.encoding" properties for backward + // compatibility reasons before falling back to the "native.encoding" property. + putIfAbsent(props, "stdin.encoding", + raw.propDefault(Raw._stdin_encoding_NDX)); + putIfAbsent(props, "stdin.encoding", nativeEncoding); putIfAbsent(props, "stdout.encoding", props.getOrDefault("sun.stdout.encoding", raw.propDefault(Raw._stdout_encoding_NDX))); putIfAbsent(props, "stdout.encoding", nativeEncoding); @@ -241,7 +244,8 @@ public static class Raw { @Native private static final int _socksProxyHost_NDX = 1 + _socksNonProxyHosts_NDX; @Native private static final int _socksProxyPort_NDX = 1 + _socksProxyHost_NDX; @Native private static final int _stderr_encoding_NDX = 1 + _socksProxyPort_NDX; - @Native private static final int _stdout_encoding_NDX = 1 + _stderr_encoding_NDX; + @Native private static final int _stdin_encoding_NDX = 1 + _stderr_encoding_NDX; + @Native private static final int _stdout_encoding_NDX = 1 + _stdin_encoding_NDX; @Native private static final int _sun_arch_abi_NDX = 1 + _stdout_encoding_NDX; @Native private static final int _sun_arch_data_model_NDX = 1 + _sun_arch_abi_NDX; @Native private static final int _sun_cpu_endian_NDX = 1 + _sun_arch_data_model_NDX; diff --git a/src/java.base/share/native/libjava/System.c b/src/java.base/share/native/libjava/System.c index b1feaf3dff7..725c1e30227 100644 --- a/src/java.base/share/native/libjava/System.c +++ b/src/java.base/share/native/libjava/System.c @@ -154,6 +154,7 @@ Java_jdk_internal_util_SystemProps_00024Raw_platformProperties(JNIEnv *env, jcla PUTPROP(propArray, _sun_jnu_encoding_NDX, sprops->sun_jnu_encoding); /* encodings for standard streams, may be NULL */ + PUTPROP(propArray, _stdin_encoding_NDX, sprops->stdin_encoding); PUTPROP(propArray, _stdout_encoding_NDX, sprops->stdout_encoding); PUTPROP(propArray, _stderr_encoding_NDX, sprops->stderr_encoding); diff --git a/src/java.base/share/native/libjava/java_props.h b/src/java.base/share/native/libjava/java_props.h index 95fb6d9e7f9..774a7435e54 100644 --- a/src/java.base/share/native/libjava/java_props.h +++ b/src/java.base/share/native/libjava/java_props.h @@ -65,6 +65,7 @@ typedef struct { char *display_variant; char *encoding; /* always set non-NULL by platform code */ char *sun_jnu_encoding; /* always set non-NULL by platform code */ + char *stdin_encoding; char *stdout_encoding; char *stderr_encoding; diff --git a/src/java.base/unix/native/libjava/java_props_md.c b/src/java.base/unix/native/libjava/java_props_md.c index 6db307088b0..1d5435d5229 100644 --- a/src/java.base/unix/native/libjava/java_props_md.c +++ b/src/java.base/unix/native/libjava/java_props_md.c @@ -464,6 +464,9 @@ GetJavaProperties(JNIEnv *env) sprops.sun_jnu_encoding = sprops.encoding; #endif + if (isatty(STDIN_FILENO) == 1) { + sprops.stdin_encoding = sprops.encoding; + } if (isatty(STDOUT_FILENO) == 1) { sprops.stdout_encoding = sprops.encoding; } diff --git a/src/java.base/windows/native/libjava/java_props_md.c b/src/java.base/windows/native/libjava/java_props_md.c index 275dd3795c5..9495faf81e5 100644 --- a/src/java.base/windows/native/libjava/java_props_md.c +++ b/src/java.base/windows/native/libjava/java_props_md.c @@ -634,7 +634,7 @@ GetJavaProperties(JNIEnv* env) LCID userDefaultUILCID = MAKELCID(userDefaultUILang, SORTIDFROMLCID(userDefaultLCID)); { - HANDLE hStdOutErr; + HANDLE hStdHandle; // Windows UI Language selection list only cares "language" // information of the UI Language. For example, the list @@ -677,14 +677,19 @@ GetJavaProperties(JNIEnv* env) sprops.sun_jnu_encoding = "MS950_HKSCS"; } - hStdOutErr = GetStdHandle(STD_OUTPUT_HANDLE); - if (hStdOutErr != INVALID_HANDLE_VALUE && - GetFileType(hStdOutErr) == FILE_TYPE_CHAR) { + hStdHandle = GetStdHandle(STD_INPUT_HANDLE); + if (hStdHandle != INVALID_HANDLE_VALUE && + GetFileType(hStdHandle) == FILE_TYPE_CHAR) { + sprops.stdin_encoding = getConsoleEncoding(FALSE); + } + hStdHandle = GetStdHandle(STD_OUTPUT_HANDLE); + if (hStdHandle != INVALID_HANDLE_VALUE && + GetFileType(hStdHandle) == FILE_TYPE_CHAR) { sprops.stdout_encoding = getConsoleEncoding(TRUE); } - hStdOutErr = GetStdHandle(STD_ERROR_HANDLE); - if (hStdOutErr != INVALID_HANDLE_VALUE && - GetFileType(hStdOutErr) == FILE_TYPE_CHAR) { + hStdHandle = GetStdHandle(STD_ERROR_HANDLE); + if (hStdHandle != INVALID_HANDLE_VALUE && + GetFileType(hStdHandle) == FILE_TYPE_CHAR) { if (sprops.stdout_encoding != NULL) sprops.stderr_encoding = sprops.stdout_encoding; else diff --git a/test/jdk/java/lang/System/PropertyTest.java b/test/jdk/java/lang/System/PropertyTest.java index ed89e36a8cd..09b0835fb6e 100644 --- a/test/jdk/java/lang/System/PropertyTest.java +++ b/test/jdk/java/lang/System/PropertyTest.java @@ -81,6 +81,7 @@ static Object[][] requiredProperties() { {"java.runtime.version"}, {"java.runtime.name"}, {"native.encoding"}, + {"stdin.encoding"}, {"stdout.encoding"}, {"stderr.encoding"}, }; From ac05002cbeb014036ffbbcb17bb12d8d2102c7cd Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 25 Apr 2025 16:34:52 +0000 Subject: [PATCH 034/118] 8354877: DirectClassBuilder default flags should include ACC_SUPER Reviewed-by: asotona --- .../jdk/internal/classfile/impl/DirectClassBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index 6dc62511639..1e12969f204 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -42,7 +42,7 @@ public final class DirectClassBuilder implements ClassBuilder { /** The value of default class access flags */ - static final int DEFAULT_CLASS_FLAGS = ClassFile.ACC_PUBLIC; + static final int DEFAULT_CLASS_FLAGS = ClassFile.ACC_PUBLIC | ClassFile.ACC_SUPER; static final Util.Writable[] EMPTY_WRITABLE_ARRAY = {}; static final ClassEntry[] EMPTY_CLASS_ENTRY_ARRAY = {}; final ClassEntry thisClassEntry; From d8f012ea2a0514020434d5db6047e36941e9349b Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Fri, 25 Apr 2025 17:06:26 +0000 Subject: [PATCH 035/118] 8305186: Reference.waitForReferenceProcessing should be more accessible to tests Reviewed-by: kbarrett --- test/lib/jdk/test/whitebox/WhiteBox.java | 51 ++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index f0e164d94b5..bd68cf72cc3 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -24,7 +24,11 @@ package jdk.test.whitebox; import java.lang.management.MemoryUsage; +import java.lang.ref.Reference; import java.lang.reflect.Executable; +import java.lang.reflect.InaccessibleObjectException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.function.BiFunction; @@ -556,6 +560,53 @@ public void clearInlineCaches(boolean preserve_static_stubs) { // Force Full GC public native void fullGC(); + // Infrastructure for waitForReferenceProcessing() + private static volatile Method waitForReferenceProcessingMethod = null; + + private static Method getWaitForReferenceProcessingMethod() { + Method wfrp = waitForReferenceProcessingMethod; + if (wfrp == null) { + try { + wfrp = Reference.class.getDeclaredMethod("waitForReferenceProcessing"); + wfrp.setAccessible(true); + assert wfrp.getReturnType() == Boolean.class; + Class[] ev = wfrp.getExceptionTypes(); + assert ev.length == 1; + assert ev[0] == InterruptedException.class; + waitForReferenceProcessingMethod = wfrp; + } catch (InaccessibleObjectException e) { + throw new RuntimeException("Need to add @modules java.base/java.lang.ref:open to test?", e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + return wfrp; + } + + /** + * Wait for reference processing, via Reference.waitForReferenceProcessing(). + * Callers of this method will need the + * @modules java.base/java.lang.ref:open + * jtreg tag. + * + * This method should usually be called after a call to WhiteBox.fullGC(). + */ + public boolean waitForReferenceProcessing() throws InterruptedException { + try { + Method wfrp = getWaitForReferenceProcessingMethod(); + return (Boolean) wfrp.invoke(null); + } catch (IllegalAccessException e) { + throw new RuntimeException("Shouldn't happen, we call setAccessible()", e); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof InterruptedException) { + throw (InterruptedException) cause; + } else { + throw new RuntimeException(e); + } + } + } + // Returns true if the current GC supports concurrent collection control. public native boolean supportsConcurrentGCBreakpoints(); From 4b880299881c9413038d647123e3b658999c6f8f Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Fri, 25 Apr 2025 17:11:54 +0000 Subject: [PATCH 036/118] 8355439: Some hotspot/jtreg/serviceability/sa/* tests fail on static JDK due to explicit checks for shared libraries in process memory map Reviewed-by: sspitsyn, cjplummer --- test/hotspot/jtreg/serviceability/sa/ClhsdbPmap.java | 8 ++++++-- .../serviceability/sa/sadebugd/PmapOnDebugdTest.java | 10 ++++++++-- .../sa/sadebugd/RunCommandOnServerTest.java | 10 ++++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbPmap.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbPmap.java index 38e572329de..9999f08208e 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbPmap.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbPmap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,11 @@ public static void main(String[] args) throws Exception { if (!withCore && Platform.isOSX()) { expStrMap.put("pmap", List.of("Not available for Mac OS X processes")); } else { - expStrMap.put("pmap", List.of("jvm", "java", "jli", "jimage")); + if (Platform.isStatic()) { + expStrMap.put("pmap", List.of("java")); + } else { + expStrMap.put("pmap", List.of("jvm", "java", "jli", "jimage")); + } } if (withCore) { diff --git a/test/hotspot/jtreg/serviceability/sa/sadebugd/PmapOnDebugdTest.java b/test/hotspot/jtreg/serviceability/sa/sadebugd/PmapOnDebugdTest.java index 82c874671f9..6c14e7823e4 100644 --- a/test/hotspot/jtreg/serviceability/sa/sadebugd/PmapOnDebugdTest.java +++ b/test/hotspot/jtreg/serviceability/sa/sadebugd/PmapOnDebugdTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021 NTT DATA. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -23,6 +23,7 @@ */ import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.Platform; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.SA.SATestUtils; @@ -65,7 +66,12 @@ public static void main(String[] args) throws Exception { System.err.println(out.getStderr()); out.stderrShouldBeEmptyIgnoreDeprecatedWarnings(); - out.shouldMatch("^0x[0-9a-f]+.+libjvm\\.so$"); // Find libjvm from output + if (Platform.isStatic()) { + out.shouldMatch("java"); // Find launcher + out.shouldNotMatch("^0x[0-9a-f]+.+libjvm\\.so$"); // No libjvm from output + } else { + out.shouldMatch("^0x[0-9a-f]+.+libjvm\\.so$"); // Find libjvm from output + } out.shouldHaveExitValue(0); // This will detect most SA failures, including during the attach. diff --git a/test/hotspot/jtreg/serviceability/sa/sadebugd/RunCommandOnServerTest.java b/test/hotspot/jtreg/serviceability/sa/sadebugd/RunCommandOnServerTest.java index 990a9667f3f..4ac5c452770 100644 --- a/test/hotspot/jtreg/serviceability/sa/sadebugd/RunCommandOnServerTest.java +++ b/test/hotspot/jtreg/serviceability/sa/sadebugd/RunCommandOnServerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021 NTT DATA. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,6 +25,7 @@ import java.io.PrintStream; import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.Platform; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.SA.SATestUtils; @@ -75,7 +76,12 @@ public static void main(String[] args) throws Exception { System.err.println(out.getStderr()); out.stderrShouldBeEmptyIgnoreDeprecatedWarnings(); - out.shouldMatch("^0x[0-9a-f]+: .+/libjvm\\.(so|dylib) \\+ 0x[0-9a-f]+$"); + if (Platform.isStatic()) { + out.shouldMatch("java"); + out.shouldNotMatch("^0x[0-9a-f]+: .+/libjvm\\.(so|dylib) \\+ 0x[0-9a-f]+$"); + } else { + out.shouldMatch("^0x[0-9a-f]+: .+/libjvm\\.(so|dylib) \\+ 0x[0-9a-f]+$"); + } out.shouldHaveExitValue(0); // This will detect most SA failures, including during the attach. From 2785570f5620db08c0d31cd29839f92ffabd58b2 Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Fri, 25 Apr 2025 20:12:45 +0000 Subject: [PATCH 037/118] 8355366: Fix the wrong usage of PassFailJFrame.forcePass() in some manual tests Reviewed-by: honkar, aivanov, prr --- test/jdk/java/awt/Desktop/BrowseTest.java | 19 +++++----- .../EditAndPrintTest/EditAndPrintTest.java | 35 ++++++++++--------- test/jdk/java/awt/Desktop/OpenTest.java | 21 +++++------ 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/test/jdk/java/awt/Desktop/BrowseTest.java b/test/jdk/java/awt/Desktop/BrowseTest.java index 1bdccace3fc..33de1ecdca7 100644 --- a/test/jdk/java/awt/Desktop/BrowseTest.java +++ b/test/jdk/java/awt/Desktop/BrowseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,8 @@ * @test * @bug 6255196 * @summary Verifies the function of method browse(java.net.URI uri). - * @library /java/awt/regtesthelpers - * @build PassFailJFrame + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException * @run main/manual BrowseTest */ @@ -36,6 +36,8 @@ import java.net.URI; import javax.swing.JPanel; +import jtreg.SkippedException; + public class BrowseTest extends JPanel { static final String INSTRUCTIONS = """ This test could launch default file manager to open user's home @@ -47,12 +49,6 @@ public class BrowseTest extends JPanel { """; public BrowseTest() { - if (!Desktop.isDesktopSupported()) { - PassFailJFrame.log("Class java.awt.Desktop is not supported on " + - "current platform. Farther testing will not be performed"); - PassFailJFrame.forcePass(); - } - Desktop desktop = Desktop.getDesktop(); URI dirURI = new File(System.getProperty("user.home")).toURI(); @@ -77,6 +73,11 @@ public BrowseTest() { public static void main(String[] args) throws InterruptedException, InvocationTargetException { + if (!Desktop.isDesktopSupported()) { + throw new SkippedException("Class java.awt.Desktop is not supported " + + "on current platform. Further testing will not be performed"); + } + PassFailJFrame.builder() .title("Browser Test") .splitUI(BrowseTest::new) diff --git a/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java b/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java index 3f161f7fcaf..b2d7ef28df1 100644 --- a/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java +++ b/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,8 @@ * @bug 6255196 * @summary Verifies the function of methods edit(java.io.File file) and * print(java.io.File file) - * @library /java/awt/regtesthelpers - * @build PassFailJFrame + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException * @run main/manual EditAndPrintTest */ @@ -40,6 +40,8 @@ import java.lang.reflect.InvocationTargetException; import javax.swing.JPanel; +import jtreg.SkippedException; + public class EditAndPrintTest extends JPanel { static final String INSTRUCTIONS = """ @@ -49,20 +51,9 @@ public class EditAndPrintTest extends JPanel { If you see any EXCEPTION messages in the output press FAIL. """; - public EditAndPrintTest() { - if (!Desktop.isDesktopSupported()) { - PassFailJFrame.log("Class java.awt.Desktop is not supported on " + - "current platform. Further testing will not be performed"); - PassFailJFrame.forcePass(); - } - - Desktop desktop = Desktop.getDesktop(); - - if (!desktop.isSupported(Action.PRINT) && !desktop.isSupported(Action.EDIT)) { - PassFailJFrame.log("Neither EDIT nor PRINT actions are supported. Nothing to test."); - PassFailJFrame.forcePass(); - } + static Desktop desktop; + public EditAndPrintTest() { /* * Part 1: print or edit a directory, which should throw an IOException. */ @@ -111,7 +102,7 @@ public EditAndPrintTest() { writer.write("This is a temp file used to test print() method of Desktop."); writer.flush(); writer.close(); - } catch (java.io.IOException ioe){ + } catch (IOException ioe){ PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); PassFailJFrame.forceFail("Failed to create temp file for testing."); } @@ -139,6 +130,16 @@ public EditAndPrintTest() { public static void main(String args[]) throws InterruptedException, InvocationTargetException { + if (!Desktop.isDesktopSupported()) { + throw new SkippedException("Class java.awt.Desktop is not supported " + + "on current platform. Further testing will not be performed"); + } + + desktop = Desktop.getDesktop(); + if (!desktop.isSupported(Action.PRINT) && !desktop.isSupported(Action.EDIT)) { + throw new SkippedException("Neither EDIT nor PRINT actions are supported. Nothing to test."); + } + PassFailJFrame.builder() .title("Edit and Print test") .splitUI(EditAndPrintTest::new) diff --git a/test/jdk/java/awt/Desktop/OpenTest.java b/test/jdk/java/awt/Desktop/OpenTest.java index 1ed29067d50..c5f2a6939e4 100644 --- a/test/jdk/java/awt/Desktop/OpenTest.java +++ b/test/jdk/java/awt/Desktop/OpenTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,8 @@ * @test * @bug 6255196 * @summary Verifies the function of method open(java.io.File file). - * @library /java/awt/regtesthelpers - * @build PassFailJFrame + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException * @run main/manual/othervm OpenTest */ @@ -36,6 +36,8 @@ import java.lang.reflect.InvocationTargetException; import javax.swing.JPanel; +import jtreg.SkippedException; + public class OpenTest extends JPanel { static final String INSTRUCTIONS = """ @@ -48,12 +50,6 @@ public class OpenTest extends JPanel { """; public OpenTest() { - if (!Desktop.isDesktopSupported()) { - PassFailJFrame.log("Class java.awt.Desktop is not supported on " + - "current platform. Further testing will not be performed"); - PassFailJFrame.forcePass(); - } - Desktop desktop = Desktop.getDesktop(); /* @@ -85,7 +81,7 @@ public OpenTest() { testFile = File.createTempFile("JDIC-test", ".txt", new File(System.getProperty("java.io.tmpdir"))); testFile.deleteOnExit(); - } catch (java.io.IOException ioe) { + } catch (IOException ioe) { PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); PassFailJFrame.log("Failed to create test file"); } @@ -101,6 +97,11 @@ public OpenTest() { public static void main(String[] args) throws InterruptedException, InvocationTargetException { + if (!Desktop.isDesktopSupported()) { + throw new SkippedException("Class java.awt.Desktop is not supported " + + "on current platform. Further testing will not be performed"); + } + PassFailJFrame.builder() .title("Mail Test") .splitUI(OpenTest::new) From 5db62abb4216a0618d6ea59d292828907572d542 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Fri, 25 Apr 2025 20:58:40 +0000 Subject: [PATCH 038/118] 8315719: Adapt AOTClassLinking test case for dynamic CDS archive Reviewed-by: ccheung --- .../resolvedConstants/ResolvedConstants.java | 90 ++++++++++++------- .../jdk/test/lib/cds/SimpleCDSAppTester.java | 5 ++ 2 files changed, 64 insertions(+), 31 deletions(-) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java b/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java index 7d3335b9db6..8fa86c3f56e 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/resolvedConstants/ResolvedConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,8 @@ */ /* - * @test - * @summary Dump time resolution of constant pool entries. + * @test id=static + * @summary Dump time resolution of constant pool entries (Static CDS archive). * @requires vm.cds * @requires vm.cds.supports.aot.class.linking * @requires vm.compMode != "Xcomp" @@ -36,12 +36,32 @@ * MyInterface InterfaceWithClinit NormalClass * OldProvider OldClass OldConsumer SubOfOldClass * StringConcatTest StringConcatTestOld - * @run driver ResolvedConstants + * @run driver ResolvedConstants STATIC + */ + +/* + * @test id=dynamic + * @summary Dump time resolution of constant pool entries (Dynamic CDS archive) + * @requires vm.cds + * @requires vm.cds.supports.aot.class.linking + * @requires vm.compMode != "Xcomp" + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes/ + * @build OldProvider OldClass OldConsumer StringConcatTestOld + * @build ResolvedConstants + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * ResolvedConstantsApp ResolvedConstantsFoo ResolvedConstantsBar + * MyInterface InterfaceWithClinit NormalClass + * OldProvider OldClass OldConsumer SubOfOldClass + * StringConcatTest StringConcatTestOld + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Dcds.app.tester.workflow=DYNAMIC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. ResolvedConstants DYNAMIC */ import java.util.function.Consumer; import jdk.test.lib.cds.CDSOptions; import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.cds.SimpleCDSAppTester; import jdk.test.lib.helpers.ClassFileInstaller; import jdk.test.lib.process.OutputAnalyzer; @@ -52,33 +72,32 @@ public class ResolvedConstants { static boolean aotClassLinking; public static void main(String[] args) throws Exception { - test(false); - test(true); + test(args, false); + test(args, true); } - static void test(boolean testMode) throws Exception { + static void test(String[] args, boolean testMode) throws Exception { aotClassLinking = testMode; - CDSTestUtils.dumpClassList(classList, "-cp", appJar, mainClass) - .assertNormalExit(output -> { - output.shouldContain("Hello ResolvedConstantsApp"); - }); - - CDSOptions opts = (new CDSOptions()) - .addPrefix("-XX:ExtraSharedClassListFile=" + classList, - "-cp", appJar, - "-Xlog:cds+resolve=trace", - "-Xlog:cds+class=debug"); - if (aotClassLinking) { - opts.addPrefix("-XX:+AOTClassLinking"); - } else { - opts.addPrefix("-XX:-AOTClassLinking"); - } - OutputAnalyzer out = CDSTestUtils.createArchiveAndCheck(opts); - // Class References --- + SimpleCDSAppTester.of("ResolvedConstantsApp" + (aotClassLinking ? "1" : "0")) + .addVmArgs(aotClassLinking ? "-XX:+AOTClassLinking" : "-XX:-AOTClassLinking", + "-Xlog:cds+resolve=trace", + "-Xlog:cds+class=debug") + .classpath(appJar) + .appCommandLine(mainClass) + .setAssemblyChecker((OutputAnalyzer out) -> { + checkAssemblyOutput(args, out); + }) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("Hello ResolvedConstantsApp"); + }) + .run(args); + } + static void checkAssemblyOutput(String args[], OutputAnalyzer out) { + testGroup("Class References", out) // Always resolve reference when a class references itself - out.shouldMatch(ALWAYS("klass.* ResolvedConstantsApp app => ResolvedConstantsApp app")) + .shouldMatch(ALWAYS("klass.* ResolvedConstantsApp app => ResolvedConstantsApp app")) // Always resolve reference when a class references a super class .shouldMatch(ALWAYS("klass.* ResolvedConstantsApp app => java/lang/Object boot")) @@ -92,10 +111,9 @@ static void test(boolean testMode) throws Exception { // Even though System is in the vmClasses list, when ResolvedConstantsApp looks up // "java/lang/System" in its ConstantPool, the app loader may not have resolved the System // class yet (i.e., there's no initiaited class entry for System in the app loader's dictionary) - .shouldMatch(AOTLINK_ONLY("klass.* ResolvedConstantsApp .*java/lang/System")) - - // Field References --- + .shouldMatch(AOTLINK_ONLY("klass.* ResolvedConstantsApp .*java/lang/System")); + testGroup("Field References", out) // Always resolve references to fields in the current class or super class(es) .shouldMatch(ALWAYS("field.* ResolvedConstantsBar => ResolvedConstantsBar.b:I")) .shouldMatch(ALWAYS("field.* ResolvedConstantsBar => ResolvedConstantsBar.a:I")) @@ -108,10 +126,14 @@ static void test(boolean testMode) throws Exception { // Resolve field references to unrelated classes ONLY when using -XX:+AOTClassLinking .shouldMatch(AOTLINK_ONLY("field.* ResolvedConstantsApp => ResolvedConstantsBar.a:I")) - .shouldMatch(AOTLINK_ONLY("field.* ResolvedConstantsApp => ResolvedConstantsBar.b:I")) + .shouldMatch(AOTLINK_ONLY("field.* ResolvedConstantsApp => ResolvedConstantsBar.b:I")); - // Method References --- + if (args[0].equals("DYNAMIC")) { + // AOT resolution of CP methods/indy references is not implemeted + return; + } + testGroup("Method References", out) // Should resolve references to own constructor .shouldMatch(ALWAYS("method.* ResolvedConstantsApp ResolvedConstantsApp.:")) // Should resolve references to super constructor @@ -148,7 +170,8 @@ static void test(boolean testMode) throws Exception { // Indy References --- if (aotClassLinking) { - out.shouldContain("Cannot aot-resolve Lambda proxy because OldConsumer is excluded") + testGroup("Indy References", out) + .shouldContain("Cannot aot-resolve Lambda proxy because OldConsumer is excluded") .shouldContain("Cannot aot-resolve Lambda proxy because OldProvider is excluded") .shouldContain("Cannot aot-resolve Lambda proxy because OldClass is excluded") .shouldContain("Cannot aot-resolve Lambda proxy of interface type InterfaceWithClinit") @@ -170,6 +193,11 @@ static String AOTLINK_ONLY(String s) { return "cds,resolve.*reverted " + s; } } + + static OutputAnalyzer testGroup(String name, OutputAnalyzer out) { + System.out.println("Checking for: " + name); + return out; + } } class ResolvedConstantsApp implements Runnable { diff --git a/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java b/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java index 16666676a2f..7ab28ebb369 100644 --- a/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java +++ b/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java @@ -173,4 +173,9 @@ public SimpleCDSAppTester runAOTWorkflow() throws Exception { (new Tester(name)).runAOTWorkflow(); return this; } + + public SimpleCDSAppTester run(String args[]) throws Exception { + (new Tester(name)).run(args); + return this; + } } From e57fd710496b2ac8aa93eb3d4ff2234170fa2e37 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 25 Apr 2025 21:22:37 +0000 Subject: [PATCH 039/118] 8353786: Migrate Vector API math library support to FFM API Reviewed-by: jbhateja, kvn, psandoz, xgong, jvernee, mli --- src/hotspot/cpu/aarch64/aarch64.ad | 4 +- .../cpu/aarch64/stubGenerator_aarch64.cpp | 75 ---- .../cpu/aarch64/vm_version_aarch64.cpp | 9 +- src/hotspot/cpu/arm/vm_version_arm_32.cpp | 4 +- src/hotspot/cpu/ppc/vm_version_ppc.cpp | 6 +- src/hotspot/cpu/riscv/riscv.ad | 4 +- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 54 --- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 2 +- src/hotspot/cpu/s390/vm_version_s390.cpp | 32 +- src/hotspot/cpu/s390/vm_version_s390.hpp | 2 +- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 64 ---- src/hotspot/cpu/x86/vm_version_x86.cpp | 12 +- src/hotspot/cpu/x86/x86_64.ad | 7 +- src/hotspot/cpu/zero/vm_version_zero.cpp | 2 +- .../linux_riscv/vm_version_linux_riscv.cpp | 7 +- src/hotspot/share/ci/ciInstance.cpp | 6 + src/hotspot/share/ci/ciInstance.hpp | 1 + src/hotspot/share/classfile/modules.cpp | 4 - src/hotspot/share/classfile/vmIntrinsics.hpp | 26 +- src/hotspot/share/jvmci/jvmci_globals.cpp | 3 +- src/hotspot/share/jvmci/jvmci_globals.hpp | 4 +- src/hotspot/share/opto/c2_globals.hpp | 3 - src/hotspot/share/opto/c2compiler.cpp | 3 + src/hotspot/share/opto/library_call.cpp | 4 + src/hotspot/share/opto/library_call.hpp | 1 + src/hotspot/share/opto/vectorIntrinsics.cpp | 233 +++++++------ src/hotspot/share/prims/vectorSupport.cpp | 56 +-- src/hotspot/share/prims/vectorSupport.hpp | 26 -- src/hotspot/share/prims/whitebox.cpp | 2 +- .../share/runtime/abstract_vm_version.cpp | 14 + .../share/runtime/abstract_vm_version.hpp | 6 + src/hotspot/share/runtime/arguments.cpp | 5 - src/hotspot/share/runtime/os.cpp | 2 +- src/hotspot/share/runtime/stubRoutines.cpp | 2 - src/hotspot/share/runtime/stubRoutines.hpp | 4 - src/hotspot/share/runtime/vmStructs.cpp | 1 + .../classes/jdk/internal/vm/vector/Utils.java | 49 +++ .../jdk/internal/vm/vector/VectorSupport.java | 50 ++- src/java.base/share/classes/module-info.java | 1 + .../jdk/incubator/vector/ByteVector.java | 7 +- .../jdk/incubator/vector/CPUFeatures.java | 83 +++++ .../jdk/incubator/vector/DoubleVector.java | 27 ++ .../jdk/incubator/vector/FloatVector.java | 27 ++ .../jdk/incubator/vector/IntVector.java | 7 +- .../jdk/incubator/vector/LongVector.java | 7 +- .../jdk/incubator/vector/ShortVector.java | 7 +- .../classes/jdk/incubator/vector/Util.java | 33 ++ .../incubator/vector/VectorMathLibrary.java | 323 ++++++++++++++++++ .../jdk/incubator/vector/VectorOperators.java | 41 +-- .../incubator/vector/X-Vector.java.template | 43 ++- 50 files changed, 920 insertions(+), 475 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/vm/vector/Utils.java create mode 100644 src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java create mode 100644 src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Util.java create mode 100644 src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 3d25e97c0c5..c11c960911f 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2306,11 +2306,11 @@ const RegMask* Matcher::predicate_reg_mask(void) { } bool Matcher::supports_vector_calling_convention(void) { - return EnableVectorSupport && UseVectorStubs; + return EnableVectorSupport; } OptoRegPair Matcher::vector_return_value(uint ideal_reg) { - assert(EnableVectorSupport && UseVectorStubs, "sanity"); + assert(EnableVectorSupport, "sanity"); int lo = V0_num; int hi = V0_H_num; if (ideal_reg == Op_VecX || ideal_reg == Op_VecA) { diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index a6cc757f6a0..f5567dcc03a 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -11166,79 +11166,6 @@ class StubGenerator: public StubCodeGenerator { // } }; - void generate_vector_math_stubs() { - // Get native vector math stub routine addresses - void* libsleef = nullptr; - char ebuf[1024]; - char dll_name[JVM_MAXPATHLEN]; - if (os::dll_locate_lib(dll_name, sizeof(dll_name), Arguments::get_dll_dir(), "sleef")) { - libsleef = os::dll_load(dll_name, ebuf, sizeof ebuf); - } - if (libsleef == nullptr) { - log_info(library)("Failed to load native vector math library, %s!", ebuf); - return; - } - // Method naming convention - // All the methods are named as _ - // Where: - // is the operation name, e.g. sin - // is optional to indicate float/double - // "f/d" for vector float/double operation - // is the number of elements in the vector - // "2/4" for neon, and "x" for sve - // is the precision level - // "u10/u05" represents 1.0/0.5 ULP error bounds - // We use "u10" for all operations by default - // But for those functions do not have u10 support, we use "u05" instead - // indicates neon/sve - // "sve/advsimd" for sve/neon implementations - // e.g. sinfx_u10sve is the method for computing vector float sin using SVE instructions - // cosd2_u10advsimd is the method for computing 2 elements vector double cos using NEON instructions - // - log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "sleef" JNI_LIB_SUFFIX, p2i(libsleef)); - - // Math vector stubs implemented with SVE for scalable vector size. - if (UseSVE > 0) { - for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { - int vop = VectorSupport::VECTOR_OP_MATH_START + op; - // Skip "tanh" because there is performance regression - if (vop == VectorSupport::VECTOR_OP_TANH) { - continue; - } - - // The native library does not support u10 level of "hypot". - const char* ulf = (vop == VectorSupport::VECTOR_OP_HYPOT) ? "u05" : "u10"; - - snprintf(ebuf, sizeof(ebuf), "%sfx_%ssve", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf); - - snprintf(ebuf, sizeof(ebuf), "%sdx_%ssve", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf); - } - } - - // Math vector stubs implemented with NEON for 64/128 bits vector size. - for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { - int vop = VectorSupport::VECTOR_OP_MATH_START + op; - // Skip "tanh" because there is performance regression - if (vop == VectorSupport::VECTOR_OP_TANH) { - continue; - } - - // The native library does not support u10 level of "hypot". - const char* ulf = (vop == VectorSupport::VECTOR_OP_HYPOT) ? "u05" : "u10"; - - snprintf(ebuf, sizeof(ebuf), "%sf4_%sadvsimd", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libsleef, ebuf); - - snprintf(ebuf, sizeof(ebuf), "%sf4_%sadvsimd", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libsleef, ebuf); - - snprintf(ebuf, sizeof(ebuf), "%sd2_%sadvsimd", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libsleef, ebuf); - } - } - // Initialization void generate_initial_stubs() { // Generate initial stubs and initializes the entry points @@ -11392,8 +11319,6 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_montgomerySquare = g.generate_multiply(); } - generate_vector_math_stubs(); - #endif // COMPILER2 if (UseChaCha20Intrinsics) { diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index b2d34553487..6ed7a6be585 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -642,6 +642,7 @@ void VM_Version::initialize() { if (_model2) { os::snprintf_checked(buf + buf_used_len, sizeof(buf) - buf_used_len, "(0x%03x)", _model2); } + size_t features_offset = strnlen(buf, sizeof(buf)); #define ADD_FEATURE_IF_SUPPORTED(id, name, bit) \ do { \ if (VM_Version::supports_##name()) strcat(buf, ", " #name); \ @@ -649,7 +650,11 @@ void VM_Version::initialize() { CPU_FEATURE_FLAGS(ADD_FEATURE_IF_SUPPORTED) #undef ADD_FEATURE_IF_SUPPORTED - _features_string = os::strdup(buf); + _cpu_info_string = os::strdup(buf); + + _features_string = extract_features_string(_cpu_info_string, + strnlen(_cpu_info_string, sizeof(buf)), + features_offset); } #if defined(LINUX) @@ -716,7 +721,7 @@ void VM_Version::initialize_cpu_information(void) { int desc_len = snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "AArch64 "); get_compatible_board(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len); desc_len = (int)strlen(_cpu_desc); - snprintf(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _features_string); + snprintf(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/cpu/arm/vm_version_arm_32.cpp b/src/hotspot/cpu/arm/vm_version_arm_32.cpp index 148786a55da..d0941936035 100644 --- a/src/hotspot/cpu/arm/vm_version_arm_32.cpp +++ b/src/hotspot/cpu/arm/vm_version_arm_32.cpp @@ -295,7 +295,7 @@ void VM_Version::initialize() { (has_multiprocessing_extensions() ? ", mp_ext" : "")); // buf is started with ", " or is empty - _features_string = os::strdup(buf); + _cpu_info_string = os::strdup(buf); if (has_simd()) { if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { @@ -363,6 +363,6 @@ void VM_Version::initialize_cpu_information(void) { _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "ARM%d", _arm_arch); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _features_string); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index 8ec69bffe15..3cb0bf9bf72 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -219,7 +219,7 @@ void VM_Version::initialize() { (has_brw() ? " brw" : "") // Make sure number of %s matches num_features! ); - _features_string = os::strdup(buf); + _cpu_info_string = os::strdup(buf); if (Verbose) { print_features(); } @@ -519,7 +519,7 @@ void VM_Version::print_platform_virtualization_info(outputStream* st) { } void VM_Version::print_features() { - tty->print_cr("Version: %s L1_data_cache_line_size=%d", features_string(), L1_data_cache_line_size()); + tty->print_cr("Version: %s L1_data_cache_line_size=%d", cpu_info_string(), L1_data_cache_line_size()); if (Verbose) { if (ContendedPaddingWidth > 0) { @@ -726,6 +726,6 @@ void VM_Version::initialize_cpu_information(void) { _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "PowerPC POWER%lu", PowerArchitecturePPC64); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", features_string()); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 2e9d25c8156..83c16ce5d82 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1950,11 +1950,11 @@ const RegMask* Matcher::predicate_reg_mask(void) { // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { - return EnableVectorSupport && UseVectorStubs; + return EnableVectorSupport; } OptoRegPair Matcher::vector_return_value(uint ideal_reg) { - assert(EnableVectorSupport && UseVectorStubs, "sanity"); + assert(EnableVectorSupport, "sanity"); assert(ideal_reg == Op_VecA, "sanity"); // check more info at https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc int lo = V8_num; diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 4527a32926f..fb4539267ae 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -6458,58 +6458,6 @@ static const int64_t right_3_bits = right_n_bits(3); return start; } - void generate_vector_math_stubs() { - if (!UseRVV) { - log_info(library)("vector is not supported, skip loading vector math (sleef) library!"); - return; - } - - // Get native vector math stub routine addresses - void* libsleef = nullptr; - char ebuf[1024]; - char dll_name[JVM_MAXPATHLEN]; - if (os::dll_locate_lib(dll_name, sizeof(dll_name), Arguments::get_dll_dir(), "sleef")) { - libsleef = os::dll_load(dll_name, ebuf, sizeof ebuf); - } - if (libsleef == nullptr) { - log_info(library)("Failed to load native vector math (sleef) library, %s!", ebuf); - return; - } - - // Method naming convention - // All the methods are named as _ - // - // Where: - // is the operation name, e.g. sin, cos - // is to indicate float/double - // "fx/dx" for vector float/double operation - // is the precision level - // "u10/u05" represents 1.0/0.5 ULP error bounds - // We use "u10" for all operations by default - // But for those functions do not have u10 support, we use "u05" instead - // rvv, indicates riscv vector extension - // - // e.g. sinfx_u10rvv is the method for computing vector float sin using rvv instructions - // - log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "sleef" JNI_LIB_SUFFIX, p2i(libsleef)); - - for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { - int vop = VectorSupport::VECTOR_OP_MATH_START + op; - if (vop == VectorSupport::VECTOR_OP_TANH) { // skip tanh because of performance regression - continue; - } - - // The native library does not support u10 level of "hypot". - const char* ulf = (vop == VectorSupport::VECTOR_OP_HYPOT) ? "u05" : "u10"; - - snprintf(ebuf, sizeof(ebuf), "%sfx_%srvv", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf); - - snprintf(ebuf, sizeof(ebuf), "%sdx_%srvv", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf); - } - } - #endif // COMPILER2 /** @@ -6741,8 +6689,6 @@ static const int64_t right_3_bits = right_n_bits(3); generate_string_indexof_stubs(); - generate_vector_math_stubs(); - #endif // COMPILER2 } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 8dcffc9c646..28c32ed33c8 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -468,7 +468,7 @@ void VM_Version::initialize_cpu_information(void) { _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "RISCV64"); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", features_string()); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index 157b945e6e1..8261fbd083a 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -90,7 +90,7 @@ static const char* z_features[] = {" ", void VM_Version::initialize() { determine_features(); // Get processor capabilities. - set_features_string(); // Set a descriptive feature indication. + set_cpu_info_string(); // Set a descriptive feature indication. if (Verbose || PrintAssembly || PrintStubCode) { print_features_internal("CPU Version as detected internally:", PrintAssembly || PrintStubCode); @@ -388,9 +388,9 @@ int VM_Version::get_model_index() { } -void VM_Version::set_features_string() { - // A note on the _features_string format: - // There are jtreg tests checking the _features_string for various properties. +void VM_Version::set_cpu_info_string() { + // A note on the _cpu_info_string format: + // There are jtreg tests checking the _cpu_info_string for various properties. // For some strange reason, these tests require the string to contain // only _lowercase_ characters. Keep that in mind when being surprised // about the unusual notation of features - and when adding new ones. @@ -412,29 +412,29 @@ void VM_Version::set_features_string() { _model_string = "unknown model"; strcpy(buf, "z/Architecture (ambiguous detection)"); } - _features_string = os::strdup(buf); + _cpu_info_string = os::strdup(buf); if (has_Crypto_AES()) { - assert(strlen(_features_string) + 3*8 < sizeof(buf), "increase buffer size"); + assert(strlen(_cpu_info_string) + 3*8 < sizeof(buf), "increase buffer size"); jio_snprintf(buf, sizeof(buf), "%s%s%s%s", - _features_string, + _cpu_info_string, has_Crypto_AES128() ? ", aes128" : "", has_Crypto_AES192() ? ", aes192" : "", has_Crypto_AES256() ? ", aes256" : ""); - os::free((void *)_features_string); - _features_string = os::strdup(buf); + os::free((void *)_cpu_info_string); + _cpu_info_string = os::strdup(buf); } if (has_Crypto_SHA()) { - assert(strlen(_features_string) + 6 + 2*8 + 7 < sizeof(buf), "increase buffer size"); + assert(strlen(_cpu_info_string) + 6 + 2*8 + 7 < sizeof(buf), "increase buffer size"); jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s", - _features_string, + _cpu_info_string, has_Crypto_SHA1() ? ", sha1" : "", has_Crypto_SHA256() ? ", sha256" : "", has_Crypto_SHA512() ? ", sha512" : "", has_Crypto_GHASH() ? ", ghash" : ""); - os::free((void *)_features_string); - _features_string = os::strdup(buf); + os::free((void *)_cpu_info_string); + _cpu_info_string = os::strdup(buf); } } @@ -464,7 +464,7 @@ bool VM_Version::test_feature_bit(unsigned long* featureBuffer, int featureNum, } void VM_Version::print_features_internal(const char* text, bool print_anyway) { - tty->print_cr("%s %s", text, features_string()); + tty->print_cr("%s %s", text, cpu_info_string()); tty->cr(); if (Verbose || print_anyway) { @@ -906,7 +906,7 @@ void VM_Version::set_features_from(const char* march) { err = true; } if (!err) { - set_features_string(); + set_cpu_info_string(); if (prt || PrintAssembly) { print_features_internal("CPU Version as set by cmdline option:", prt); } @@ -1542,6 +1542,6 @@ void VM_Version::initialize_cpu_information(void) { _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, "s390 %s", VM_Version::get_model_string()); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "s390 %s", features_string()); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "s390 %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/s390/vm_version_s390.hpp b/src/hotspot/cpu/s390/vm_version_s390.hpp index 49e6f5686f6..6c6eb76bf7b 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.hpp +++ b/src/hotspot/cpu/s390/vm_version_s390.hpp @@ -148,7 +148,7 @@ class VM_Version: public Abstract_VM_Version { static bool test_feature_bit(unsigned long* featureBuffer, int featureNum, unsigned int bufLen); static int get_model_index(); - static void set_features_string(); + static void set_cpu_info_string(); static void print_features_internal(const char* text, bool print_anyway=false); static void determine_features(); static long call_getFeatures(unsigned long* buffer, int buflen, int functionCode); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index b88a2bd1f8e..1a16416787d 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -4333,70 +4333,6 @@ void StubGenerator::generate_compiler_stubs() { } } - // Get svml stub routine addresses - void *libjsvml = nullptr; - char ebuf[1024]; - char dll_name[JVM_MAXPATHLEN]; - if (os::dll_locate_lib(dll_name, sizeof(dll_name), Arguments::get_dll_dir(), "jsvml")) { - libjsvml = os::dll_load(dll_name, ebuf, sizeof ebuf); - } - if (libjsvml != nullptr) { - // SVML method naming convention - // All the methods are named as __jsvml_op_ha_ - // Where: - // ha stands for high accuracy - // is optional to indicate float/double - // Set to f for vector float operation - // Omitted for vector double operation - // is the number of elements in the vector - // 1, 2, 4, 8, 16 - // e.g. 128 bit float vector has 4 float elements - // indicates the avx/sse level: - // z0 is AVX512, l9 is AVX2, e9 is AVX1 and ex is for SSE2 - // e.g. __jsvml_expf16_ha_z0 is the method for computing 16 element vector float exp using AVX 512 insns - // __jsvml_exp8_ha_z0 is the method for computing 8 element vector double exp using AVX 512 insns - - log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "jsvml" JNI_LIB_SUFFIX, p2i(libjsvml)); - if (UseAVX > 2) { - for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { - int vop = VectorSupport::VECTOR_OP_MATH_START + op; - if ((!VM_Version::supports_avx512dq()) && - (vop == VectorSupport::VECTOR_OP_LOG || vop == VectorSupport::VECTOR_OP_LOG10 || vop == VectorSupport::VECTOR_OP_POW)) { - continue; - } - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf16_ha_z0", VectorSupport::mathname[op]); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_512][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s8_ha_z0", VectorSupport::mathname[op]); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_512][op] = (address)os::dll_lookup(libjsvml, ebuf); - } - } - const char* avx_sse_str = (UseAVX >= 2) ? "l9" : ((UseAVX == 1) ? "e9" : "ex"); - for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { - int vop = VectorSupport::VECTOR_OP_MATH_START + op; - if (vop == VectorSupport::VECTOR_OP_POW) { - continue; - } - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf8_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_256][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s1_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s2_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s4_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_256][op] = (address)os::dll_lookup(libjsvml, ebuf); - } - } - #endif // COMPILER2 #endif // COMPILER2_OR_JVMCI } diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 4687edb13a3..5306f0becef 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1080,15 +1080,19 @@ void VM_Version::get_processor_features() { } char buf[1024]; - int res = jio_snprintf( + int cpu_info_size = jio_snprintf( buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d microcode 0x%x", cores_per_cpu(), threads_per_core(), cpu_family(), _model, _stepping, os::cpu_microcode_revision()); - assert(res > 0, "not enough temporary space allocated"); - insert_features_names(buf + res, sizeof(buf) - res, _features_names); + assert(cpu_info_size > 0, "not enough temporary space allocated"); + insert_features_names(buf + cpu_info_size, sizeof(buf) - cpu_info_size, _features_names); - _features_string = os::strdup(buf); + _cpu_info_string = os::strdup(buf); + + _features_string = extract_features_string(_cpu_info_string, + strnlen(_cpu_info_string, sizeof(buf)), + cpu_info_size); // Use AES instructions if available. if (supports_aes()) { diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index dc79108c6f8..954a53307c2 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -1596,14 +1596,11 @@ uint MachUEPNode::size(PhaseRegAlloc* ra_) const //============================================================================= bool Matcher::supports_vector_calling_convention(void) { - if (EnableVectorSupport && UseVectorStubs) { - return true; - } - return false; + return EnableVectorSupport; } OptoRegPair Matcher::vector_return_value(uint ideal_reg) { - assert(EnableVectorSupport && UseVectorStubs, "sanity"); + assert(EnableVectorSupport, "sanity"); int lo = XMM0_num; int hi = XMM0b_num; if (ideal_reg == Op_VecX) hi = XMM0d_num; diff --git a/src/hotspot/cpu/zero/vm_version_zero.cpp b/src/hotspot/cpu/zero/vm_version_zero.cpp index e38561e19c5..3ce9227c193 100644 --- a/src/hotspot/cpu/zero/vm_version_zero.cpp +++ b/src/hotspot/cpu/zero/vm_version_zero.cpp @@ -151,6 +151,6 @@ void VM_Version::initialize_cpu_information(void) { _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "Zero VM"); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _features_string); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index b6095c279cb..506c78cacca 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -129,6 +129,9 @@ void VM_Version::setup_cpu_available_features() { snprintf(buf, sizeof(buf)/2, "%s ", uarch); } os::free((void*) uarch); + + int features_offset = strnlen(buf, sizeof(buf)); + strcat(buf, "rv64"); int i = 0; while (_feature_list[i] != nullptr) { @@ -191,7 +194,9 @@ void VM_Version::setup_cpu_available_features() { } } - _features_string = os::strdup(buf); + _cpu_info_string = os::strdup(buf); + + _features_string = _cpu_info_string + features_offset; } void VM_Version::os_aux_features() { diff --git a/src/hotspot/share/ci/ciInstance.cpp b/src/hotspot/share/ci/ciInstance.cpp index ad456ba6726..9591298e3ab 100644 --- a/src/hotspot/share/ci/ciInstance.cpp +++ b/src/hotspot/share/ci/ciInstance.cpp @@ -138,3 +138,9 @@ ciKlass* ciInstance::java_lang_Class_klass() { assert(java_lang_Class::as_Klass(get_oop()) != nullptr, "klass is null"); return CURRENT_ENV->get_metadata(java_lang_Class::as_Klass(get_oop()))->as_klass(); } + +char* ciInstance::java_lang_String_str(char* buf, size_t buflen) { + VM_ENTRY_MARK; + assert(get_oop()->is_a(vmClasses::String_klass()), "not a String"); + return java_lang_String::as_utf8_string(get_oop(), buf, buflen); +} diff --git a/src/hotspot/share/ci/ciInstance.hpp b/src/hotspot/share/ci/ciInstance.hpp index 3af07edcd9e..1fb09985930 100644 --- a/src/hotspot/share/ci/ciInstance.hpp +++ b/src/hotspot/share/ci/ciInstance.hpp @@ -67,6 +67,7 @@ class ciInstance : public ciObject { ciConstant field_value_by_offset(int field_offset); ciKlass* java_lang_Class_klass(); + char* java_lang_String_str(char* buf, size_t buflen); }; #endif // SHARE_CI_CIINSTANCE_HPP diff --git a/src/hotspot/share/classfile/modules.cpp b/src/hotspot/share/classfile/modules.cpp index 05be2df52af..a506c4502a4 100644 --- a/src/hotspot/share/classfile/modules.cpp +++ b/src/hotspot/share/classfile/modules.cpp @@ -466,13 +466,9 @@ void Modules::define_module(Handle module, jboolean is_open, jstring version, if (EnableVectorSupport && EnableVectorReboxing && FLAG_IS_DEFAULT(EnableVectorAggressiveReboxing)) { FLAG_SET_DEFAULT(EnableVectorAggressiveReboxing, true); } - if (EnableVectorSupport && FLAG_IS_DEFAULT(UseVectorStubs)) { - FLAG_SET_DEFAULT(UseVectorStubs, true); - } log_info(compilation)("EnableVectorSupport=%s", (EnableVectorSupport ? "true" : "false")); log_info(compilation)("EnableVectorReboxing=%s", (EnableVectorReboxing ? "true" : "false")); log_info(compilation)("EnableVectorAggressiveReboxing=%s", (EnableVectorAggressiveReboxing ? "true" : "false")); - log_info(compilation)("UseVectorStubs=%s", (UseVectorStubs ? "true" : "false")); } #endif // COMPILER2_OR_JVMCI } diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 68de40f1788..2959f35ef2c 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -1001,7 +1001,8 @@ class methodHandle; do_intrinsic(_VectorUnaryOp, jdk_internal_vm_vector_VectorSupport, vector_unary_op_name, vector_unary_op_sig, F_S) \ do_signature(vector_unary_op_sig, "(I" \ "Ljava/lang/Class;" \ - "Ljava/lang/Class;Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ "I" \ "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ "Ljdk/internal/vm/vector/VectorSupport$VectorMask;" \ @@ -1022,6 +1023,29 @@ class methodHandle; "Ljdk/internal/vm/vector/VectorSupport$VectorPayload;") \ do_name(vector_binary_op_name, "binaryOp") \ \ + do_intrinsic(_VectorUnaryLibOp, jdk_internal_vm_vector_VectorSupport, vector_unary_lib_op_name, vector_unary_lib_op_sig, F_S) \ + do_signature(vector_unary_lib_op_sig,"(J" \ + "Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ + "I" \ + "Ljava/lang/String;" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ + "Ljdk/internal/vm/vector/VectorSupport$UnaryOperation;)" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;") \ + do_name(vector_unary_lib_op_name, "libraryUnaryOp") \ + \ + do_intrinsic(_VectorBinaryLibOp, jdk_internal_vm_vector_VectorSupport, vector_binary_lib_op_name, vector_binary_lib_op_sig, F_S) \ + do_signature(vector_binary_lib_op_sig,"(J" \ + "Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ + "I" \ + "Ljava/lang/String;" \ + "Ljdk/internal/vm/vector/VectorSupport$VectorPayload;" \ + "Ljdk/internal/vm/vector/VectorSupport$VectorPayload;" \ + "Ljdk/internal/vm/vector/VectorSupport$BinaryOperation;)" \ + "Ljdk/internal/vm/vector/VectorSupport$VectorPayload;") \ + do_name(vector_binary_lib_op_name, "libraryBinaryOp") \ + \ do_intrinsic(_VectorTernaryOp, jdk_internal_vm_vector_VectorSupport, vector_ternary_op_name, vector_ternary_op_sig, F_S) \ do_signature(vector_ternary_op_sig, "(I" \ "Ljava/lang/Class;" \ diff --git a/src/hotspot/share/jvmci/jvmci_globals.cpp b/src/hotspot/share/jvmci/jvmci_globals.cpp index dfc7e6b5970..a41351218f8 100644 --- a/src/hotspot/share/jvmci/jvmci_globals.cpp +++ b/src/hotspot/share/jvmci/jvmci_globals.cpp @@ -144,8 +144,9 @@ bool JVMCIGlobals::check_jvmci_flags_are_consistent() { JVMCI_FLAG_CHECKED(UseMulAddIntrinsic) JVMCI_FLAG_CHECKED(UseMontgomeryMultiplyIntrinsic) JVMCI_FLAG_CHECKED(UseMontgomerySquareIntrinsic) - JVMCI_FLAG_CHECKED(UseVectorStubs) #endif // !COMPILER2 + // + JVMCI_FLAG_CHECKED(UseVectorStubs) #ifndef PRODUCT #define JVMCI_CHECK4(type, name, value, ...) assert(name##checked, #name " flag not checked"); diff --git a/src/hotspot/share/jvmci/jvmci_globals.hpp b/src/hotspot/share/jvmci/jvmci_globals.hpp index 4da49b24e6e..5bcead9ff7b 100644 --- a/src/hotspot/share/jvmci/jvmci_globals.hpp +++ b/src/hotspot/share/jvmci/jvmci_globals.hpp @@ -184,8 +184,8 @@ class fileStream; NOT_COMPILER2(product(bool, EnableVectorAggressiveReboxing, false, EXPERIMENTAL, \ "Enables aggressive reboxing of vectors")) \ \ - NOT_COMPILER2(product(bool, UseVectorStubs, false, EXPERIMENTAL, \ - "Use stubs for vector transcendental operations")) \ + product(bool, UseVectorStubs, false, EXPERIMENTAL, \ + "Use stubs for vector transcendental operations") \ // end of JVMCI_FLAGS diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 662f2e07965..2246bd62f4e 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -760,9 +760,6 @@ product(bool, EnableVectorAggressiveReboxing, false, EXPERIMENTAL, \ "Enables aggressive reboxing of vectors") \ \ - product(bool, UseVectorStubs, false, EXPERIMENTAL, \ - "Use stubs for vector transcendental operations") \ - \ product(bool, UseTypeSpeculation, true, \ "Speculatively propagate types from profiles") \ \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index f39937b9cdd..272692446ae 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -848,6 +848,9 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_IndexVector: case vmIntrinsics::_IndexPartiallyInUpperRange: return EnableVectorSupport; + case vmIntrinsics::_VectorUnaryLibOp: + case vmIntrinsics::_VectorBinaryLibOp: + return EnableVectorSupport && Matcher::supports_vector_calling_convention(); case vmIntrinsics::_blackhole: #if INCLUDE_JVMTI case vmIntrinsics::_notifyJvmtiVThreadStart: diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 017564173a8..65635001e13 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -721,6 +721,10 @@ bool LibraryCallKit::try_to_inline(int predicate) { return inline_vector_nary_operation(1); case vmIntrinsics::_VectorBinaryOp: return inline_vector_nary_operation(2); + case vmIntrinsics::_VectorUnaryLibOp: + return inline_vector_call(1); + case vmIntrinsics::_VectorBinaryLibOp: + return inline_vector_call(2); case vmIntrinsics::_VectorTernaryOp: return inline_vector_nary_operation(3); case vmIntrinsics::_VectorFromBitsCoerced: diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index cb755267ec5..1be08df32ae 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -369,6 +369,7 @@ class LibraryCallKit : public GraphKit { // Vector API support bool inline_vector_nary_operation(int n); + bool inline_vector_call(int arity); bool inline_vector_frombits_coerced(); bool inline_vector_mask_operation(); bool inline_vector_mem_operation(bool is_store); diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index e33d7b19686..13acc0469eb 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -366,17 +366,11 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { int num_elem = vlen->get_con(); int opc = VectorSupport::vop2ideal(opr->get_con(), elem_bt); int sopc = has_scalar_op ? VectorNode::opcode(opc, elem_bt) : opc; - if ((opc != Op_CallLeafVector) && (sopc == 0)) { - log_if_needed(" ** operation not supported: opc=%s bt=%s", NodeClassNames[opc], type2name(elem_bt)); + if (sopc == 0 || num_elem == 1) { + log_if_needed(" ** operation not supported: arity=%d opc=%s[%d] vlen=%d etype=%s", + n, NodeClassNames[opc], opc, num_elem, type2name(elem_bt)); return false; // operation not supported } - if (num_elem == 1) { - if (opc != Op_CallLeafVector || elem_bt != T_DOUBLE) { - log_if_needed(" ** not a svml call: arity=%d opc=%d vlen=%d etype=%s", - n, opc, num_elem, type2name(elem_bt)); - return false; - } - } ciKlass* vbox_klass = vector_klass->const_oop()->as_instance()->java_lang_Class_klass(); const TypeInstPtr* vbox_type = TypeInstPtr::make_exact(TypePtr::NotNull, vbox_klass); @@ -384,22 +378,6 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { assert(!is_masked_op, "mask operations do not need mask to control"); } - if (opc == Op_CallLeafVector) { - if (!UseVectorStubs) { - log_if_needed(" ** vector stubs support is disabled"); - return false; - } - if (!Matcher::supports_vector_calling_convention()) { - log_if_needed(" ** no vector calling conventions supported"); - return false; - } - if (!Matcher::vector_size_supported(elem_bt, num_elem)) { - log_if_needed(" ** vector size (vlen=%d, etype=%s) is not supported", - num_elem, type2name(elem_bt)); - return false; - } - } - // When using mask, mask use type needs to be VecMaskUseLoad. VectorMaskUseType mask_use_type = is_vector_mask(vbox_klass) ? VecMaskUseAll : is_masked_op ? VecMaskUseLoad : VecMaskNotUsed; @@ -464,30 +442,18 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { } Node* operation = nullptr; - if (opc == Op_CallLeafVector) { - assert(UseVectorStubs, "sanity"); - operation = gen_call_to_vector_math(opr->get_con(), elem_bt, num_elem, opd1, opd2); - if (operation == nullptr) { - log_if_needed(" ** Vector math call failed for %s_%s_%d", - (elem_bt == T_FLOAT) ? "float" : "double", - VectorSupport::mathname[opr->get_con() - VectorSupport::VECTOR_OP_MATH_START], - num_elem * type2aelembytes(elem_bt)); - return false; - } - } else { - const TypeVect* vt = TypeVect::make(elem_bt, num_elem, is_vector_mask(vbox_klass)); - switch (n) { - case 1: - case 2: { - operation = VectorNode::make(sopc, opd1, opd2, vt, is_vector_mask(vbox_klass), VectorNode::is_shift_opcode(opc), is_unsigned); - break; - } - case 3: { - operation = VectorNode::make(sopc, opd1, opd2, opd3, vt); - break; - } - default: fatal("unsupported arity: %d", n); + const TypeVect* vt = TypeVect::make(elem_bt, num_elem, is_vector_mask(vbox_klass)); + switch (n) { + case 1: + case 2: { + operation = VectorNode::make(sopc, opd1, opd2, vt, is_vector_mask(vbox_klass), VectorNode::is_shift_opcode(opc), is_unsigned); + break; + } + case 3: { + operation = VectorNode::make(sopc, opd1, opd2, opd3, vt); + break; } + default: fatal("unsupported arity: %d", n); } if (is_masked_op && mask != nullptr) { @@ -510,6 +476,107 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { } // public static +// , E> +// V libraryUnaryOp(long address, Class vClass, Class elementType, int length, String debugName, +// V v, +// UnaryOperation defaultImpl) +// +// public static +// +// V libraryBinaryOp(long address, Class vClass, Class elementType, int length, String debugName, +// V v1, V v2, +// BinaryOperation defaultImpl) +bool LibraryCallKit::inline_vector_call(int arity) { + assert(Matcher::supports_vector_calling_convention(), "required"); + + const TypeLong* entry = gvn().type(argument(0))->isa_long(); + const TypeInstPtr* vector_klass = gvn().type(argument(2))->isa_instptr(); + const TypeInstPtr* elem_klass = gvn().type(argument(3))->isa_instptr(); + const TypeInt* vlen = gvn().type(argument(4))->isa_int(); + const TypeInstPtr* debug_name_oop = gvn().type(argument(5))->isa_instptr(); + + if (entry == nullptr || !entry->is_con() || + vector_klass == nullptr || vector_klass->const_oop() == nullptr || + elem_klass == nullptr || elem_klass->const_oop() == nullptr || + vlen == nullptr || !vlen->is_con() || + debug_name_oop == nullptr || debug_name_oop->const_oop() == nullptr) { + log_if_needed(" ** missing constant: opr=%s vclass=%s etype=%s vlen=%s debug_name=%s", + NodeClassNames[argument(0)->Opcode()], + NodeClassNames[argument(2)->Opcode()], + NodeClassNames[argument(3)->Opcode()], + NodeClassNames[argument(4)->Opcode()], + NodeClassNames[argument(5)->Opcode()]); + return false; // not enough info for intrinsification + } + + if (entry->get_con() == 0) { + log_if_needed(" ** missing entry point"); + return false; + } + + ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type(); + if (!elem_type->is_primitive_type()) { + log_if_needed(" ** not a primitive bt=%d", elem_type->basic_type()); + return false; // should be primitive type + } + if (!is_klass_initialized(vector_klass)) { + log_if_needed(" ** klass argument not initialized"); + return false; + } + + BasicType elem_bt = elem_type->basic_type(); + int num_elem = vlen->get_con(); + if (!Matcher::vector_size_supported(elem_bt, num_elem)) { + log_if_needed(" ** vector size (vlen=%d, etype=%s) is not supported", + num_elem, type2name(elem_bt)); + return false; + } + + ciKlass* vbox_klass = vector_klass->const_oop()->as_instance()->java_lang_Class_klass(); + const TypeInstPtr* vbox_type = TypeInstPtr::make_exact(TypePtr::NotNull, vbox_klass); + + Node* opd1 = unbox_vector(argument(6), vbox_type, elem_bt, num_elem); + if (opd1 == nullptr) { + log_if_needed(" ** unbox failed v1=%s", NodeClassNames[argument(6)->Opcode()]); + return false; + } + + Node* opd2 = nullptr; + if (arity > 1) { + opd2 = unbox_vector(argument(7), vbox_type, elem_bt, num_elem); + if (opd2 == nullptr) { + log_if_needed(" ** unbox failed v2=%s", NodeClassNames[argument(7)->Opcode()]); + return false; + } + } + assert(arity == 1 || arity == 2, "arity %d not supported", arity); + const TypeVect* vt = TypeVect::make(elem_bt, num_elem); + const TypeFunc* call_type = OptoRuntime::Math_Vector_Vector_Type(arity, vt, vt); + address entry_addr = (address)entry->get_con(); + + const char* debug_name = ""; + if (!debug_name_oop->const_oop()->is_null_object()) { + size_t buflen = 100; + char* buf = NEW_ARENA_ARRAY(C->comp_arena(), char, buflen); + debug_name = debug_name_oop->const_oop()->as_instance()->java_lang_String_str(buf, buflen); + } + Node* vcall = make_runtime_call(RC_VECTOR, + call_type, + entry_addr, + debug_name, + TypePtr::BOTTOM, + opd1, + opd2); + + vcall = gvn().transform(new ProjNode(gvn().transform(vcall), TypeFunc::Parms)); + + // Wrap it up in VectorBox to keep object type information. + Node* vbox = box_vector(vcall, vbox_type, elem_bt, num_elem); + set_result(vbox); + C->set_max_vector_size(MAX2(C->max_vector_size(), (uint)(num_elem * type2aelembytes(elem_bt)))); + return true; +} + // // long maskReductionCoerced(int oper, Class maskClass, Class elemClass, // int length, M m, VectorMaskOp defaultImpl) @@ -1844,50 +1911,6 @@ bool LibraryCallKit::inline_vector_rearrange() { return true; } -static address get_vector_math_address(int vop, int bits, BasicType bt, char* name_ptr, int name_len) { - address addr = nullptr; - assert(UseVectorStubs, "sanity"); - assert(name_ptr != nullptr, "unexpected"); - assert((vop >= VectorSupport::VECTOR_OP_MATH_START) && (vop <= VectorSupport::VECTOR_OP_MATH_END), "unexpected"); - int op = vop - VectorSupport::VECTOR_OP_MATH_START; - - switch(bits) { - case 64: //fallthough - case 128: //fallthough - case 256: //fallthough - case 512: - if (bt == T_FLOAT) { - snprintf(name_ptr, name_len, "vector_%s_float_%dbits_fixed", VectorSupport::mathname[op], bits); - addr = StubRoutines::_vector_f_math[exact_log2(bits/64)][op]; - } else { - assert(bt == T_DOUBLE, "must be FP type only"); - snprintf(name_ptr, name_len, "vector_%s_double_%dbits_fixed", VectorSupport::mathname[op], bits); - addr = StubRoutines::_vector_d_math[exact_log2(bits/64)][op]; - } - break; - default: - if (!Matcher::supports_scalable_vector() || !Matcher::vector_size_supported(bt, bits/type2aelembytes(bt)) ) { - snprintf(name_ptr, name_len, "invalid"); - addr = nullptr; - Unimplemented(); - } - break; - } - - if (addr == nullptr && Matcher::supports_scalable_vector()) { - if (bt == T_FLOAT) { - snprintf(name_ptr, name_len, "vector_%s_float_%dbits_scalable", VectorSupport::mathname[op], bits); - addr = StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_SCALABLE][op]; - } else { - assert(bt == T_DOUBLE, "must be FP type only"); - snprintf(name_ptr, name_len, "vector_%s_double_%dbits_scalable", VectorSupport::mathname[op], bits); - addr = StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_SCALABLE][op]; - } - } - - return addr; -} - // public static // , // M extends VectorMask, @@ -2044,32 +2067,6 @@ bool LibraryCallKit::inline_vector_select_from() { return true; } -Node* LibraryCallKit::gen_call_to_vector_math(int vector_api_op_id, BasicType bt, int num_elem, Node* opd1, Node* opd2) { - assert(UseVectorStubs, "sanity"); - assert(vector_api_op_id >= VectorSupport::VECTOR_OP_MATH_START && vector_api_op_id <= VectorSupport::VECTOR_OP_MATH_END, "need valid op id"); - assert(opd1 != nullptr, "must not be null"); - const TypeVect* vt = TypeVect::make(bt, num_elem); - const TypeFunc* call_type = OptoRuntime::Math_Vector_Vector_Type(opd2 != nullptr ? 2 : 1, vt, vt); - char name[100] = ""; - - // Get address for vector math method. - address addr = get_vector_math_address(vector_api_op_id, vt->length_in_bytes() * BitsPerByte, bt, name, 100); - - if (addr == nullptr) { - return nullptr; - } - - assert(name[0] != '\0', "name must not be null"); - Node* operation = make_runtime_call(RC_VECTOR, - call_type, - addr, - name, - TypePtr::BOTTOM, - opd1, - opd2); - return gvn().transform(new ProjNode(gvn().transform(operation), TypeFunc::Parms)); -} - // public static // , // M extends VectorMask, diff --git a/src/hotspot/share/prims/vectorSupport.cpp b/src/hotspot/share/prims/vectorSupport.cpp index a00656f30ee..c907ddb4885 100644 --- a/src/hotspot/share/prims/vectorSupport.cpp +++ b/src/hotspot/share/prims/vectorSupport.cpp @@ -39,31 +39,9 @@ #include "runtime/stackValue.hpp" #ifdef COMPILER2 #include "opto/matcher.hpp" +#include "opto/vectornode.hpp" #endif // COMPILER2 -#ifdef COMPILER2 -const char* VectorSupport::mathname[VectorSupport::NUM_VECTOR_OP_MATH] = { - "tan", - "tanh", - "sin", - "sinh", - "cos", - "cosh", - "asin", - "acos", - "atan", - "atan2", - "cbrt", - "log", - "log10", - "log1p", - "pow", - "exp", - "expm1", - "hypot", -}; -#endif - bool VectorSupport::is_vector(Klass* klass) { return klass->is_subclass_of(vmClasses::vector_VectorPayload_klass()); } @@ -615,25 +593,6 @@ int VectorSupport::vop2ideal(jint id, BasicType bt) { break; } - case VECTOR_OP_TAN: - case VECTOR_OP_TANH: - case VECTOR_OP_SIN: - case VECTOR_OP_SINH: - case VECTOR_OP_COS: - case VECTOR_OP_COSH: - case VECTOR_OP_ASIN: - case VECTOR_OP_ACOS: - case VECTOR_OP_ATAN: - case VECTOR_OP_ATAN2: - case VECTOR_OP_CBRT: - case VECTOR_OP_LOG: - case VECTOR_OP_LOG10: - case VECTOR_OP_LOG1P: - case VECTOR_OP_POW: - case VECTOR_OP_EXP: - case VECTOR_OP_EXPM1: - case VECTOR_OP_HYPOT: - return Op_CallLeafVector; default: fatal("unknown op: %d", vop); } return 0; // Unimplemented @@ -655,16 +614,26 @@ JVM_ENTRY(jint, VectorSupport_GetMaxLaneCount(JNIEnv *env, jclass vsclazz, jobje return -1; } JVM_END +JVM_ENTRY(jstring, VectorSupport_GetCPUFeatures(JNIEnv* env, jclass ignored)) + const char* features_string = VM_Version::features_string(); + assert(features_string != nullptr, "missing cpu features info"); + + oop result = java_lang_String::create_oop_from_str(features_string, CHECK_NULL); + return (jstring) JNIHandles::make_local(THREAD, result); +JVM_END + // JVM_RegisterVectorSupportMethods #define LANG "Ljava/lang/" #define CLS LANG "Class;" +#define LSTR LANG "String;" #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) static JNINativeMethod jdk_internal_vm_vector_VectorSupport_methods[] = { - {CC "getMaxLaneCount", CC "(" CLS ")I", FN_PTR(VectorSupport_GetMaxLaneCount)} + {CC "getMaxLaneCount", CC "(" CLS ")I", FN_PTR(VectorSupport_GetMaxLaneCount)}, + {CC "getCPUFeatures", CC "()" LSTR, FN_PTR(VectorSupport_GetCPUFeatures)} }; #undef CC @@ -672,6 +641,7 @@ static JNINativeMethod jdk_internal_vm_vector_VectorSupport_methods[] = { #undef LANG #undef CLS +#undef LSTR // This function is exported, used by NativeLookup. diff --git a/src/hotspot/share/prims/vectorSupport.hpp b/src/hotspot/share/prims/vectorSupport.hpp index 688fb595099..5ba18cdfaa8 100644 --- a/src/hotspot/share/prims/vectorSupport.hpp +++ b/src/hotspot/share/prims/vectorSupport.hpp @@ -101,36 +101,12 @@ class VectorSupport : AllStatic { VECTOR_OP_COMPRESS_BITS = 33, VECTOR_OP_EXPAND_BITS = 34, - // Vector Math Library - VECTOR_OP_TAN = 101, - VECTOR_OP_TANH = 102, - VECTOR_OP_SIN = 103, - VECTOR_OP_SINH = 104, - VECTOR_OP_COS = 105, - VECTOR_OP_COSH = 106, - VECTOR_OP_ASIN = 107, - VECTOR_OP_ACOS = 108, - VECTOR_OP_ATAN = 109, - VECTOR_OP_ATAN2 = 110, - VECTOR_OP_CBRT = 111, - VECTOR_OP_LOG = 112, - VECTOR_OP_LOG10 = 113, - VECTOR_OP_LOG1P = 114, - VECTOR_OP_POW = 115, - VECTOR_OP_EXP = 116, - VECTOR_OP_EXPM1 = 117, - VECTOR_OP_HYPOT = 118, - VECTOR_OP_SADD = 119, VECTOR_OP_SSUB = 120, VECTOR_OP_SUADD = 121, VECTOR_OP_SUSUB = 122, VECTOR_OP_UMIN = 123, VECTOR_OP_UMAX = 124, - - VECTOR_OP_MATH_START = VECTOR_OP_TAN, - VECTOR_OP_MATH_END = VECTOR_OP_HYPOT, - NUM_VECTOR_OP_MATH = VECTOR_OP_MATH_END - VECTOR_OP_MATH_START + 1 }; enum { @@ -147,8 +123,6 @@ class VectorSupport : AllStatic { MODE_BITS_COERCED_LONG_TO_MASK = 1 }; - static const char* mathname[VectorSupport::NUM_VECTOR_OP_MATH]; - static int vop2ideal(jint vop, BasicType bt); static bool has_scalar_op(jint id); static bool is_unsigned_op(jint id); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index e08a5ba5ebd..41f32729cd4 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1533,7 +1533,7 @@ WB_ENTRY(void, WB_ReadReservedMemory(JNIEnv* env, jobject o)) WB_END WB_ENTRY(jstring, WB_GetCPUFeatures(JNIEnv* env, jobject o)) - const char* features = VM_Version::features_string(); + const char* features = VM_Version::cpu_info_string(); ThreadToNativeFromVM ttn(thread); jstring features_string = env->NewStringUTF(features); diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index e95c96b4e9c..c0667d739ce 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -34,6 +34,7 @@ const char* Abstract_VM_Version::_s_internal_vm_info_string = Abstract_VM_Versio uint64_t Abstract_VM_Version::_features = 0; const char* Abstract_VM_Version::_features_string = ""; +const char* Abstract_VM_Version::_cpu_info_string = ""; uint64_t Abstract_VM_Version::_cpu_features = 0; #ifndef SUPPORTS_NATIVE_CX8 @@ -340,6 +341,19 @@ void Abstract_VM_Version::insert_features_names(char* buf, size_t buflen, const } } +const char* Abstract_VM_Version::extract_features_string(const char* cpu_info_string, + size_t cpu_info_string_len, + size_t features_offset) { + assert(features_offset <= cpu_info_string_len, ""); + if (features_offset < cpu_info_string_len) { + assert(cpu_info_string[features_offset + 0] == ',', ""); + assert(cpu_info_string[features_offset + 1] == ' ', ""); + return cpu_info_string + features_offset + 2; // skip initial ", " + } else { + return ""; // empty + } +} + bool Abstract_VM_Version::print_matching_lines_from_file(const char* filename, outputStream* st, const char* keywords_to_match[]) { char line[500]; FILE* fp = os::fopen(filename, "r"); diff --git a/src/hotspot/share/runtime/abstract_vm_version.hpp b/src/hotspot/share/runtime/abstract_vm_version.hpp index 8cfc7031f97..6f1b886bc98 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.hpp +++ b/src/hotspot/share/runtime/abstract_vm_version.hpp @@ -58,6 +58,8 @@ class Abstract_VM_Version: AllStatic { static uint64_t _features; static const char* _features_string; + static const char* _cpu_info_string; + // Original CPU feature flags, not affected by VM settings. static uint64_t _cpu_features; @@ -128,7 +130,11 @@ class Abstract_VM_Version: AllStatic { static uint64_t features() { return _features; } static const char* features_string() { return _features_string; } + static const char* cpu_info_string() { return _cpu_info_string; } static void insert_features_names(char* buf, size_t buflen, const char* features_names[]); + static const char* extract_features_string(const char* cpu_info_string, + size_t cpu_info_string_len, + size_t features_offset); static VirtualizationType get_detected_virtualization() { return _detected_virtualization; diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index d0bba58b508..69d37a11e45 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -3786,11 +3786,6 @@ jint Arguments::apply_ergo() { } } FLAG_SET_DEFAULT(EnableVectorAggressiveReboxing, false); - - if (!FLAG_IS_DEFAULT(UseVectorStubs) && UseVectorStubs) { - warning("Disabling UseVectorStubs since EnableVectorSupport is turned off."); - } - FLAG_SET_DEFAULT(UseVectorStubs, false); } #endif // COMPILER2_OR_JVMCI diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 67b25be8eb9..a58be403827 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1168,7 +1168,7 @@ void os::print_cpu_info(outputStream* st, char* buf, size_t buflen) { // We access the raw value here because the assert in the accessor will // fail if the crash occurs before initialization of this value. st->print(" (initial active %d)", _initial_active_processor_count); - st->print(" %s", VM_Version::features_string()); + st->print(" %s", VM_Version::cpu_info_string()); st->cr(); pd_print_cpu_info(st, buf, buflen); } diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index b1b1f1d6056..358434938f2 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -101,8 +101,6 @@ jint StubRoutines::_verify_oop_count = 0; address StubRoutines::_string_indexof_array[4] = { nullptr }; -address StubRoutines::_vector_f_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_VECTOR_OP_MATH] = {{nullptr}, {nullptr}}; -address StubRoutines::_vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_VECTOR_OP_MATH] = {{nullptr}, {nullptr}}; const char* StubRoutines::get_blob_name(StubGenBlobId id) { assert(0 <= id && id < StubGenBlobId::NUM_BLOBIDS, "invalid blob id"); diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index 3189415a6c5..7548a97ced8 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -305,10 +305,6 @@ class StubRoutines: AllStatic { /* special case: stub employs array of entries */ - // Vector Math Routines - static address _vector_f_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_VECTOR_OP_MATH]; - static address _vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_VECTOR_OP_MATH]; - static bool is_stub_code(address addr) { return contains(addr); } // generate code to implement method contains diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index f865380fdb7..77fae3becb5 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -702,6 +702,7 @@ static_field(Abstract_VM_Version, _s_internal_vm_info_string, const char*) \ static_field(Abstract_VM_Version, _features, uint64_t) \ static_field(Abstract_VM_Version, _features_string, const char*) \ + static_field(Abstract_VM_Version, _cpu_info_string, const char*) \ static_field(Abstract_VM_Version, _vm_major_version, int) \ static_field(Abstract_VM_Version, _vm_minor_version, int) \ static_field(Abstract_VM_Version, _vm_security_version, int) \ diff --git a/src/java.base/share/classes/jdk/internal/vm/vector/Utils.java b/src/java.base/share/classes/jdk/internal/vm/vector/Utils.java new file mode 100644 index 00000000000..de0bb83d39d --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/vm/vector/Utils.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.vm.vector; + +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; + +/** + * Miscellaneous utility methods. + */ +public class Utils { + public static final boolean DEBUG = Boolean.getBoolean("jdk.incubator.vector.DEBUG"); + + public static boolean isNonCapturingLambda(Object o) { + return o.getClass().getDeclaredFields().length == 0; + } + + @CallerSensitive + public static void debug(String format, Object... args) { + if (DEBUG) { + Class caller = Reflection.getCallerClass(); + System.out.printf("DEBUG: %s: ", caller.getSimpleName()); + System.out.printf(format, args); + System.out.println(); + } + } +} diff --git a/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java b/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java index cbf30da2289..4a8ad79b50c 100644 --- a/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java @@ -30,6 +30,8 @@ import java.util.function.*; +import static jdk.internal.vm.vector.Utils.isNonCapturingLambda; + public class VectorSupport { static { registerNatives(); @@ -114,6 +116,9 @@ public class VectorSupport { public static final int VECTOR_OP_EXPM1 = 117; public static final int VECTOR_OP_HYPOT = 118; + public static final int VECTOR_OP_MATHLIB_FIRST = VECTOR_OP_TAN; + public static final int VECTOR_OP_MATHLIB_LAST = VECTOR_OP_HYPOT; + public static final int VECTOR_OP_SADD = 119; public static final int VECTOR_OP_SSUB = 120; public static final int VECTOR_OP_SUADD = 121; @@ -323,6 +328,23 @@ V unaryOp(int oprId, /* ============================================================================ */ +// public interface LibraryUnaryOperation, +// M extends VectorMask> { +// V apply(MemorySegment entry, V v, M m); +// } + + @IntrinsicCandidate + public static + , E> + V libraryUnaryOp(long addr, Class vClass, Class eClass, int length, String debugName, + V v, + UnaryOperation defaultImpl) { + assert isNonCapturingLambda(defaultImpl) : defaultImpl; + return defaultImpl.apply(v, null); + } + + /* ============================================================================ */ + public interface BinaryOperation> { VM apply(VM v1, VM v2, M m); @@ -341,6 +363,24 @@ VM binaryOp(int oprId, assert isNonCapturingLambda(defaultImpl) : defaultImpl; return defaultImpl.apply(v1, v2, m); } + + /* ============================================================================ */ + +// public interface LibraryBinaryOperation> { +// V apply(MemorySegment entry, V v1, V v2, M m); +// } + + @IntrinsicCandidate + public static + + V libraryBinaryOp(long addr, Class vClass, Class eClass, int length, String debugName, + V v1, V v2, + BinaryOperation defaultImpl) { + assert isNonCapturingLambda(defaultImpl) : defaultImpl; + return defaultImpl.apply(v1, v2, null); + } + /* ============================================================================ */ public interface SelectFromTwoVector> { @@ -718,13 +758,19 @@ long maskReductionCoerced(int oper, /* ============================================================================ */ + // Returns a string containing a list of CPU features VM detected. + public static native String getCPUFeatures(); + + /* ============================================================================ */ + // query the JVM's supported vector sizes and types public static native int getMaxLaneCount(Class etype); /* ============================================================================ */ - public static boolean isNonCapturingLambda(Object o) { - return o.getClass().getDeclaredFields().length == 0; + @SuppressWarnings({"restricted"}) + public static void loadNativeLibrary(String name) { + System.loadLibrary(name); } /* ============================================================================ */ diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 22f40d9cead..6775dda269a 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -272,6 +272,7 @@ java.security.jgss, java.smartcardio, jdk.charsets, + jdk.incubator.vector, jdk.internal.vm.ci, jdk.jlink, jdk.jpackage, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java index ed8d273ff37..2b1cc879e66 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java @@ -689,7 +689,7 @@ ByteVector lanewiseTemplate(VectorOperators.Unary op) { if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0)); } - if (op == NOT) { + else if (op == NOT) { return broadcast(-1).lanewise(XOR, this); } } @@ -717,7 +717,7 @@ ByteVector lanewiseTemplate(VectorOperators.Unary op, if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0, m)); } - if (op == NOT) { + else if (op == NOT) { return lanewise(XOR, broadcast(-1), m); } } @@ -728,6 +728,7 @@ opc, getClass(), maskClass, byte.class, length(), UN_IMPL.find(op, opc, ByteVector::unaryOperations)); } + private static final ImplCache>> UN_IMPL = new ImplCache<>(Unary.class, ByteVector.class); @@ -824,6 +825,7 @@ ByteVector lanewiseTemplate(VectorOperators.Binary op, = this.compare(EQ, (byte) 0, m); return this.blend(that, mask); } + if (opKind(op, VO_SHIFT)) { // As per shift specification for Java, mask the shift count. // This allows the JIT to ignore some ISA details. @@ -850,6 +852,7 @@ opc, getClass(), maskClass, byte.class, length(), BIN_IMPL.find(op, opc, ByteVector::binaryOperations)); } + private static final ImplCache>> BIN_IMPL = new ImplCache<>(Binary.class, ByteVector.class); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java new file mode 100644 index 00000000000..1d44860ab86 --- /dev/null +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.incubator.vector; + +import jdk.internal.vm.vector.VectorSupport; + +import java.util.Locale; +import java.util.Set; + +import static jdk.incubator.vector.Util.requires; +import static jdk.internal.util.Architecture.isX64; +import static jdk.internal.vm.vector.Utils.debug; + +/** + * Enumerates CPU ISA extensions supported by the JVM on the current hardware. + */ +/*package-private*/ class CPUFeatures { + private static final Set features = getCPUFeatures(); + + private static Set getCPUFeatures() { + String featuresString = VectorSupport.getCPUFeatures(); + debug(featuresString); + String[] features = featuresString.toLowerCase(Locale.ROOT) + .split(",? "); // " " or ", " are used as a delimiter by JVM + assert validateFeatures(features); + return Set.of(features); + } + + private static boolean validateFeatures(String[] features) { + for (String s : features) { + assert s != null && s.matches("[a-z0-9._]+") : String.format("Invalid CPU feature name: '%s'", s); + } + return true; + } + + private static boolean hasFeature(String feature) { + return features.contains(feature.toLowerCase(Locale.ROOT)); + } + + public static class X64 { + public static boolean SUPPORTS_AVX = hasFeature("avx"); + public static boolean SUPPORTS_AVX2 = hasFeature("avx2"); + public static boolean SUPPORTS_AVX512F = hasFeature("avx512f"); + public static boolean SUPPORTS_AVX512DQ = hasFeature("avx512dq"); + + static { + requires(isX64(), "unsupported platform"); + + debug("AVX=%b; AVX2=%b; AVX512F=%b; AVX512DQ=%b", + SUPPORTS_AVX, SUPPORTS_AVX2, SUPPORTS_AVX512F, SUPPORTS_AVX512DQ); + + assert SUPPORTS_AVX512F == (VectorShape.getMaxVectorBitSize(int.class) == 512); + assert SUPPORTS_AVX2 == (VectorShape.getMaxVectorBitSize(byte.class) >= 256); + assert SUPPORTS_AVX == (VectorShape.getMaxVectorBitSize(float.class) >= 256); + } + } + + public static Set features() { + return features; + } +} diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index 5fbf02f87bd..48446c6fa01 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -678,6 +678,9 @@ DoubleVector lanewiseTemplate(VectorOperators.Unary op) { if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0)); } + else if (opKind(op, VO_MATHLIB)) { + return unaryMathOp(op); + } } int opc = opCode(op); return VectorSupport.unaryOp( @@ -703,6 +706,9 @@ DoubleVector lanewiseTemplate(VectorOperators.Unary op, if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0, m)); } + else if (opKind(op, VO_MATHLIB)) { + return blend(unaryMathOp(op), m); + } } int opc = opCode(op); return VectorSupport.unaryOp( @@ -711,6 +717,13 @@ opc, getClass(), maskClass, double.class, length(), UN_IMPL.find(op, opc, DoubleVector::unaryOperations)); } + @ForceInline + final + DoubleVector unaryMathOp(VectorOperators.Unary op) { + return VectorMathLibrary.unaryMathOp(op, opCode(op), species(), DoubleVector::unaryOperations, + this); + } + private static final ImplCache>> UN_IMPL = new ImplCache<>(Unary.class, DoubleVector.class); @@ -781,6 +794,9 @@ DoubleVector lanewiseTemplate(VectorOperators.Binary op, = this.viewAsIntegralLanes().compare(EQ, (long) 0); return this.blend(that, mask.cast(vspecies())); } + else if (opKind(op, VO_MATHLIB)) { + return binaryMathOp(op, that); + } } int opc = opCode(op); @@ -815,6 +831,10 @@ DoubleVector lanewiseTemplate(VectorOperators.Binary op, = bits.compare(EQ, (long) 0, m.cast(bits.vspecies())); return this.blend(that, mask.cast(vspecies())); } + else if (opKind(op, VO_MATHLIB)) { + return this.blend(binaryMathOp(op, that), m); + } + } int opc = opCode(op); @@ -824,6 +844,13 @@ opc, getClass(), maskClass, double.class, length(), BIN_IMPL.find(op, opc, DoubleVector::binaryOperations)); } + @ForceInline + final + DoubleVector binaryMathOp(VectorOperators.Binary op, DoubleVector that) { + return VectorMathLibrary.binaryMathOp(op, opCode(op), species(), DoubleVector::binaryOperations, + this, that); + } + private static final ImplCache>> BIN_IMPL = new ImplCache<>(Binary.class, DoubleVector.class); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index 26fbe64742d..1e0829a3b1c 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -678,6 +678,9 @@ FloatVector lanewiseTemplate(VectorOperators.Unary op) { if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0)); } + else if (opKind(op, VO_MATHLIB)) { + return unaryMathOp(op); + } } int opc = opCode(op); return VectorSupport.unaryOp( @@ -703,6 +706,9 @@ FloatVector lanewiseTemplate(VectorOperators.Unary op, if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0, m)); } + else if (opKind(op, VO_MATHLIB)) { + return blend(unaryMathOp(op), m); + } } int opc = opCode(op); return VectorSupport.unaryOp( @@ -711,6 +717,13 @@ opc, getClass(), maskClass, float.class, length(), UN_IMPL.find(op, opc, FloatVector::unaryOperations)); } + @ForceInline + final + FloatVector unaryMathOp(VectorOperators.Unary op) { + return VectorMathLibrary.unaryMathOp(op, opCode(op), species(), FloatVector::unaryOperations, + this); + } + private static final ImplCache>> UN_IMPL = new ImplCache<>(Unary.class, FloatVector.class); @@ -781,6 +794,9 @@ FloatVector lanewiseTemplate(VectorOperators.Binary op, = this.viewAsIntegralLanes().compare(EQ, (int) 0); return this.blend(that, mask.cast(vspecies())); } + else if (opKind(op, VO_MATHLIB)) { + return binaryMathOp(op, that); + } } int opc = opCode(op); @@ -815,6 +831,10 @@ FloatVector lanewiseTemplate(VectorOperators.Binary op, = bits.compare(EQ, (int) 0, m.cast(bits.vspecies())); return this.blend(that, mask.cast(vspecies())); } + else if (opKind(op, VO_MATHLIB)) { + return this.blend(binaryMathOp(op, that), m); + } + } int opc = opCode(op); @@ -824,6 +844,13 @@ opc, getClass(), maskClass, float.class, length(), BIN_IMPL.find(op, opc, FloatVector::binaryOperations)); } + @ForceInline + final + FloatVector binaryMathOp(VectorOperators.Binary op, FloatVector that) { + return VectorMathLibrary.binaryMathOp(op, opCode(op), species(), FloatVector::binaryOperations, + this, that); + } + private static final ImplCache>> BIN_IMPL = new ImplCache<>(Binary.class, FloatVector.class); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java index 076a66ed6a5..b691527bec6 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java @@ -689,7 +689,7 @@ IntVector lanewiseTemplate(VectorOperators.Unary op) { if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0)); } - if (op == NOT) { + else if (op == NOT) { return broadcast(-1).lanewise(XOR, this); } } @@ -717,7 +717,7 @@ IntVector lanewiseTemplate(VectorOperators.Unary op, if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0, m)); } - if (op == NOT) { + else if (op == NOT) { return lanewise(XOR, broadcast(-1), m); } } @@ -728,6 +728,7 @@ opc, getClass(), maskClass, int.class, length(), UN_IMPL.find(op, opc, IntVector::unaryOperations)); } + private static final ImplCache>> UN_IMPL = new ImplCache<>(Unary.class, IntVector.class); @@ -824,6 +825,7 @@ IntVector lanewiseTemplate(VectorOperators.Binary op, = this.compare(EQ, (int) 0, m); return this.blend(that, mask); } + if (opKind(op, VO_SHIFT)) { // As per shift specification for Java, mask the shift count. // This allows the JIT to ignore some ISA details. @@ -850,6 +852,7 @@ opc, getClass(), maskClass, int.class, length(), BIN_IMPL.find(op, opc, IntVector::binaryOperations)); } + private static final ImplCache>> BIN_IMPL = new ImplCache<>(Binary.class, IntVector.class); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java index 21903aa6794..9e4dcd23d67 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java @@ -647,7 +647,7 @@ LongVector lanewiseTemplate(VectorOperators.Unary op) { if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0)); } - if (op == NOT) { + else if (op == NOT) { return broadcast(-1).lanewise(XOR, this); } } @@ -675,7 +675,7 @@ LongVector lanewiseTemplate(VectorOperators.Unary op, if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0, m)); } - if (op == NOT) { + else if (op == NOT) { return lanewise(XOR, broadcast(-1), m); } } @@ -686,6 +686,7 @@ opc, getClass(), maskClass, long.class, length(), UN_IMPL.find(op, opc, LongVector::unaryOperations)); } + private static final ImplCache>> UN_IMPL = new ImplCache<>(Unary.class, LongVector.class); @@ -782,6 +783,7 @@ LongVector lanewiseTemplate(VectorOperators.Binary op, = this.compare(EQ, (long) 0, m); return this.blend(that, mask); } + if (opKind(op, VO_SHIFT)) { // As per shift specification for Java, mask the shift count. // This allows the JIT to ignore some ISA details. @@ -808,6 +810,7 @@ opc, getClass(), maskClass, long.class, length(), BIN_IMPL.find(op, opc, LongVector::binaryOperations)); } + private static final ImplCache>> BIN_IMPL = new ImplCache<>(Binary.class, LongVector.class); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java index 0bb97da8244..46df27309ae 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java @@ -689,7 +689,7 @@ ShortVector lanewiseTemplate(VectorOperators.Unary op) { if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0)); } - if (op == NOT) { + else if (op == NOT) { return broadcast(-1).lanewise(XOR, this); } } @@ -717,7 +717,7 @@ ShortVector lanewiseTemplate(VectorOperators.Unary op, if (op == ZOMO) { return blend(broadcast(-1), compare(NE, 0, m)); } - if (op == NOT) { + else if (op == NOT) { return lanewise(XOR, broadcast(-1), m); } } @@ -728,6 +728,7 @@ opc, getClass(), maskClass, short.class, length(), UN_IMPL.find(op, opc, ShortVector::unaryOperations)); } + private static final ImplCache>> UN_IMPL = new ImplCache<>(Unary.class, ShortVector.class); @@ -824,6 +825,7 @@ ShortVector lanewiseTemplate(VectorOperators.Binary op, = this.compare(EQ, (short) 0, m); return this.blend(that, mask); } + if (opKind(op, VO_SHIFT)) { // As per shift specification for Java, mask the shift count. // This allows the JIT to ignore some ISA details. @@ -850,6 +852,7 @@ opc, getClass(), maskClass, short.class, length(), BIN_IMPL.find(op, opc, ShortVector::binaryOperations)); } + private static final ImplCache>> BIN_IMPL = new ImplCache<>(Binary.class, ShortVector.class); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Util.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Util.java new file mode 100644 index 00000000000..8562d4b5d7a --- /dev/null +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Util.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.incubator.vector; + +/*package-private*/ class Util { + public static void requires(boolean cond, String message) { + if (!cond) { + throw new InternalError(message); + } + } +} diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java new file mode 100644 index 00000000000..1dfd6f131d2 --- /dev/null +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.incubator.vector; + +import jdk.internal.util.StaticProperty; +import jdk.internal.vm.annotation.DontInline; +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; +import jdk.internal.vm.vector.VectorSupport; + +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.util.function.IntFunction; + +import static jdk.incubator.vector.Util.requires; +import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.util.Architecture.*; +import static jdk.internal.vm.vector.Utils.debug; + +/** + * A wrapper for native vector math libraries bundled with the JDK (SVML and SLEEF). + * Binds vector operations to native implementations provided by the libraries. + */ +/*package-private*/ class VectorMathLibrary { + private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); + + interface Library { + String symbolName(Operator op, VectorSpecies vspecies); + boolean isSupported(Operator op, VectorSpecies vspecies); + + String SVML = "svml"; + String SLEEF = "sleef"; + String JAVA = "java"; + + static Library getInstance() { + String libraryName = System.getProperty("jdk.incubator.vector.VectorMathLibrary", getDefaultName()); + try { + return switch (libraryName) { + case SVML -> new SVML(); + case SLEEF -> new SLEEF(); + case JAVA -> new Java(); + default -> throw new IllegalArgumentException("Unsupported vector math library: " + libraryName); + }; + } catch (Throwable e) { + debug("Error during initialization of %s library: %s", libraryName, e); + return new Java(); // fallback + } + } + + static String getDefaultName() { + return switch (StaticProperty.osArch()) { + case "amd64", "x86_64" -> SVML; + case "aarch64", "riscv64" -> SLEEF; + default -> JAVA; + }; + } + } + + private static final Library LIBRARY = Library.getInstance(); + + static { + debug("%s library is used (cpu features: %s)", LIBRARY.getClass().getSimpleName(), CPUFeatures.features()); + } + + private static class Java implements Library { + @Override + public String symbolName(Operator op, VectorSpecies vspecies) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isSupported(Operator op, VectorSpecies vspecies) { + return false; // always use default implementation + } + } + + /** + * Naming convention in SVML vector math library. + * All the methods are named as __jsvml__ha_ where: + * ha stands for high accuracy + * is optional to indicate float/double + * Set to f for vector float operation + * Omitted for vector double operation + * is the number of elements in the vector + * 1, 2, 4, 8, 16 + * e.g. 128 bit float vector has 4 float elements + * indicates the avx/sse level: + * z0 is AVX512, l9 is AVX2, e9 is AVX1 and ex is for SSE2 + * e.g. __jsvml_expf16_ha_z0 is the method for computing 16 element vector float exp using AVX 512 insns + * __jsvml_exp8_ha_z0 is the method for computing 8 element vector double exp using AVX 512 insns + */ + private static class SVML implements Library { + static { + loadNativeLibrary(); + } + + private static void loadNativeLibrary() { + requires(isX64(), "SVML library is x64-specific"); + VectorSupport.loadNativeLibrary("jsvml"); + } + + private static String suffix(VectorSpecies vspecies) { + assert vspecies.vectorBitSize() <= VectorShape.getMaxVectorBitSize(vspecies.elementType()); + + if (vspecies.vectorBitSize() == 512) { + assert CPUFeatures.X64.SUPPORTS_AVX512F; + return "z0"; + } else if (CPUFeatures.X64.SUPPORTS_AVX2) { + return "l9"; + } else if (CPUFeatures.X64.SUPPORTS_AVX) { + return "e9"; + } else { + return "ex"; + } + } + + @Override + public String symbolName(Operator op, VectorSpecies vspecies) { + String suffix = suffix(vspecies); + String elemType = (vspecies.elementType() == float.class ? "f" : ""); + int vlen = (vspecies == FloatVector.SPECIES_64 ? 4 : vspecies.length()); // reuse 128-bit variant for 64-bit float vectors + return String.format("__jsvml_%s%s%d_ha_%s", op.operatorName(), elemType, vlen, suffix); + } + + @Override + public boolean isSupported(Operator op, VectorSpecies vspecies) { + Class etype = vspecies.elementType(); + if (etype != float.class && etype != double.class) { + return false; // only FP types are supported + } + int maxLaneCount = VectorSupport.getMaxLaneCount(vspecies.elementType()); + if (vspecies.length() > maxLaneCount) { + return false; // lacking vector support (either hardware or disabled on JVM side) + } + if (vspecies == DoubleVector.SPECIES_64) { + return false; // 64-bit double vectors are not supported + } + if (vspecies.vectorBitSize() == 512) { + if (op == LOG || op == LOG10 || op == POW) { + return CPUFeatures.X64.SUPPORTS_AVX512DQ; // requires AVX512DQ CPU support + } + } else if (op == POW) { + return false; // not supported + } + return true; + } + } + + /** + * Naming convention in SLEEF-based vector math library . + * All the methods are named as _ where: + * is the operation name, e.g. sin + * is optional to indicate float/double + * "f/d" for vector float/double operation + * is the number of elements in the vector + * "2/4" for neon, and "x" for sve/rvv + * is the precision level + * "u10/u05" represents 1.0/0.5 ULP error bounds + * We use "u10" for all operations by default + * But for those functions do not have u10 support, we use "u05" instead + * indicates neon/sve/rvv + * "sve/advsimd/rvv" for sve/neon/rvv implementations + * e.g. sinfx_u10sve is the method for computing vector float sin using SVE instructions + * cosd2_u10advsimd is the method for computing 2 elements vector double cos using NEON instructions + */ + private static class SLEEF implements Library { + static { + VectorSupport.loadNativeLibrary("sleef"); + } + + private static String suffix(VectorShape vshape, boolean isShapeAgnostic) { + if (isAARCH64()) { + if (isShapeAgnostic) { + return "sve"; + } else { + return "advsimd"; + } + } else if (isRISCV64()) { + assert isShapeAgnostic : "not supported"; + return "rvv"; + } else { + throw new InternalError("unsupported platform"); + } + } + + private static String precisionLevel(Operator op) { + return (op == HYPOT ? "u05" : "u10"); + } + + @Override + public String symbolName(Operator op, VectorSpecies vspecies) { + int vlen = (vspecies == FloatVector.SPECIES_64 ? 4 : vspecies.length()); // reuse 128-bit variant for 64-bit float vectors + boolean isShapeAgnostic = isRISCV64() || (isAARCH64() && vspecies.vectorBitSize() > 128); + return String.format("%s%s%s_%s%s", op.operatorName(), + (vspecies.elementType() == float.class ? "f" : "d"), + (isShapeAgnostic ? "x" : Integer.toString(vlen)), + precisionLevel(op), + suffix(vspecies.vectorShape(), isShapeAgnostic)); + } + + @Override + public boolean isSupported(Operator op, VectorSpecies vspecies) { + Class etype = vspecies.elementType(); + if (etype != float.class && etype != double.class) { + return false; // only FP element types are supported + } + int maxLaneCount = VectorSupport.getMaxLaneCount(vspecies.elementType()); + if (vspecies.length() > maxLaneCount) { + return false; // lacking vector support (either hardware or disabled on JVM side) + } + if (vspecies == DoubleVector.SPECIES_64) { + return false; // 64-bit double vectors are not supported + } + if (op == TANH) { + return false; // skip due to performance considerations + } + return true; + } + } + + private static final int SIZE = VectorSupport.VECTOR_OP_MATHLIB_LAST - VectorSupport.VECTOR_OP_MATHLIB_FIRST + 1; + + private record Entry (String name, MemorySegment entry, T impl) {} + + private static final @Stable Entry[][][] LIBRARY_ENTRIES = new Entry[SIZE][LaneType.SK_LIMIT][VectorShape.SK_LIMIT]; // OP x SHAPE x TYPE + + @ForceInline + private static Entry lookup(Operator op, int opc, VectorSpecies vspecies, IntFunction implSupplier) { + int idx = opc - VectorSupport.VECTOR_OP_MATHLIB_FIRST; + int elem_idx = ((AbstractSpecies)vspecies).laneType.switchKey; + int shape_idx = vspecies.vectorShape().switchKey; + @SuppressWarnings({"unchecked"}) + Entry entry = (Entry)LIBRARY_ENTRIES[idx][elem_idx][shape_idx]; + if (entry == null) { + entry = constructEntry(op, opc, vspecies, implSupplier); + LIBRARY_ENTRIES[idx][elem_idx][shape_idx] = entry; + } + return entry; + } + + @DontInline + private static + + Entry constructEntry(Operator op, int opc, VectorSpecies vspecies, IntFunction implSupplier) { + if (LIBRARY.isSupported(op, vspecies)) { + String symbol = LIBRARY.symbolName(op, vspecies); + try { + MemorySegment addr = LOOKUP.findOrThrow(symbol); + debug("%s %s => 0x%016x\n", op, symbol, addr.address()); + T impl = implSupplier.apply(opc); // TODO: should call the very same native implementation eventually (once FFM API supports vectors) + return new Entry<>(symbol, addr, impl); + } catch (RuntimeException e) { + throw new InternalError("not supported: " + op + " " + vspecies + " " + symbol, e); + } + } else { + return new Entry<>(null, MemorySegment.NULL, implSupplier.apply(opc)); + } + } + + @ForceInline + /*package-private*/ static + > + V unaryMathOp(Unary op, int opc, VectorSpecies vspecies, + IntFunction> implSupplier, + V v) { + var entry = lookup(op, opc, vspecies, implSupplier); + + long entryAddress = entry.entry.address(); + if (entryAddress != 0) { + @SuppressWarnings({"unchecked"}) + Class vt = (Class)vspecies.vectorType(); + return VectorSupport.libraryUnaryOp( + entry.entry.address(), vt, vspecies.elementType(), vspecies.length(), entry.name, + v, + entry.impl); + } else { + return entry.impl.apply(v, null); + } + } + + @ForceInline + /*package-private*/ static + > + V binaryMathOp(Binary op, int opc, VectorSpecies vspecies, + IntFunction> implSupplier, + V v1, V v2) { + var entry = lookup(op, opc, vspecies, implSupplier); + + long entryAddress = entry.entry.address(); + if (entryAddress != 0) { + @SuppressWarnings({"unchecked"}) + Class vt = (Class)vspecies.vectorType(); + return VectorSupport.libraryBinaryOp( + entry.entry.address(), vt, vspecies.elementType(), vspecies.length(), entry.name, + v1, v2, + entry.impl); + } else { + return entry.impl.apply(v1, v2, null); + } + } +} diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java index c5fe6dd4441..0e231bd5174 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java @@ -33,6 +33,8 @@ import jdk.internal.vm.vector.VectorSupport; +import static jdk.internal.vm.vector.Utils.isNonCapturingLambda; + /** * This class consists solely of static constants * that describe lane-wise vector operations, plus nested interfaces @@ -426,6 +428,7 @@ static boolean opKind(Operator op, int bit) { VO_SPECIAL = 0x080, // random special handling VO_NOFP = 0x100, VO_ONLYFP = 0x200, + VO_MATHLIB = 0x400, VO_OPCODE_VALID = 0x800, VO_OPCODE_SHIFT = 12, VO_OPCODE_LIMIT = 0x400, @@ -476,67 +479,67 @@ static boolean opKind(Operator op, int bit) { /** Produce {@code sin(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary SIN = unary("SIN", "sin", VectorSupport.VECTOR_OP_SIN, VO_ONLYFP); + public static final /*float*/ Unary SIN = unary("SIN", "sin", VectorSupport.VECTOR_OP_SIN, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code cos(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary COS = unary("COS", "cos", VectorSupport.VECTOR_OP_COS, VO_ONLYFP); + public static final /*float*/ Unary COS = unary("COS", "cos", VectorSupport.VECTOR_OP_COS, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code tan(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary TAN = unary("TAN", "tan", VectorSupport.VECTOR_OP_TAN, VO_ONLYFP); + public static final /*float*/ Unary TAN = unary("TAN", "tan", VectorSupport.VECTOR_OP_TAN, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code asin(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary ASIN = unary("ASIN", "asin", VectorSupport.VECTOR_OP_ASIN, VO_ONLYFP); + public static final /*float*/ Unary ASIN = unary("ASIN", "asin", VectorSupport.VECTOR_OP_ASIN, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code acos(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary ACOS = unary("ACOS", "acos", VectorSupport.VECTOR_OP_ACOS, VO_ONLYFP); + public static final /*float*/ Unary ACOS = unary("ACOS", "acos", VectorSupport.VECTOR_OP_ACOS, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code atan(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary ATAN = unary("ATAN", "atan", VectorSupport.VECTOR_OP_ATAN, VO_ONLYFP); + public static final /*float*/ Unary ATAN = unary("ATAN", "atan", VectorSupport.VECTOR_OP_ATAN, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code exp(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary EXP = unary("EXP", "exp", VectorSupport.VECTOR_OP_EXP, VO_ONLYFP); + public static final /*float*/ Unary EXP = unary("EXP", "exp", VectorSupport.VECTOR_OP_EXP, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code log(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary LOG = unary("LOG", "log", VectorSupport.VECTOR_OP_LOG, VO_ONLYFP); + public static final /*float*/ Unary LOG = unary("LOG", "log", VectorSupport.VECTOR_OP_LOG, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code log10(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary LOG10 = unary("LOG10", "log10", VectorSupport.VECTOR_OP_LOG10, VO_ONLYFP); + public static final /*float*/ Unary LOG10 = unary("LOG10", "log10", VectorSupport.VECTOR_OP_LOG10, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code sqrt(a)}. Floating only. See section "Operations on floating point vectors" above */ public static final /*float*/ Unary SQRT = unary("SQRT", "sqrt", VectorSupport.VECTOR_OP_SQRT, VO_ONLYFP); /** Produce {@code cbrt(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary CBRT = unary("CBRT", "cbrt", VectorSupport.VECTOR_OP_CBRT, VO_ONLYFP); + public static final /*float*/ Unary CBRT = unary("CBRT", "cbrt", VectorSupport.VECTOR_OP_CBRT, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code sinh(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary SINH = unary("SINH", "sinh", VectorSupport.VECTOR_OP_SINH, VO_ONLYFP); + public static final /*float*/ Unary SINH = unary("SINH", "sinh", VectorSupport.VECTOR_OP_SINH, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code cosh(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary COSH = unary("COSH", "cosh", VectorSupport.VECTOR_OP_COSH, VO_ONLYFP); + public static final /*float*/ Unary COSH = unary("COSH", "cosh", VectorSupport.VECTOR_OP_COSH, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code tanh(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary TANH = unary("TANH", "tanh", VectorSupport.VECTOR_OP_TANH, VO_ONLYFP); + public static final /*float*/ Unary TANH = unary("TANH", "tanh", VectorSupport.VECTOR_OP_TANH, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code expm1(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary EXPM1 = unary("EXPM1", "expm1", VectorSupport.VECTOR_OP_EXPM1, VO_ONLYFP); + public static final /*float*/ Unary EXPM1 = unary("EXPM1", "expm1", VectorSupport.VECTOR_OP_EXPM1, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code log1p(a)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Unary LOG1P = unary("LOG1P", "log1p", VectorSupport.VECTOR_OP_LOG1P, VO_ONLYFP); + public static final /*float*/ Unary LOG1P = unary("LOG1P", "log1p", VectorSupport.VECTOR_OP_LOG1P, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); // Binary operators @@ -615,15 +618,15 @@ static boolean opKind(Operator op, int bit) { /** Produce {@code atan2(a,b)}. See Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Binary ATAN2 = binary("ATAN2", "atan2", VectorSupport.VECTOR_OP_ATAN2, VO_ONLYFP); + public static final /*float*/ Binary ATAN2 = binary("ATAN2", "atan2", VectorSupport.VECTOR_OP_ATAN2, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code pow(a,b)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Binary POW = binary("POW", "pow", VectorSupport.VECTOR_OP_POW, VO_ONLYFP); + public static final /*float*/ Binary POW = binary("POW", "pow", VectorSupport.VECTOR_OP_POW, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); /** Produce {@code hypot(a,b)}. Floating only. * Not guaranteed to be semi-monotonic. See section "Operations on floating point vectors" above */ - public static final /*float*/ Binary HYPOT = binary("HYPOT", "hypot", VectorSupport.VECTOR_OP_HYPOT, VO_ONLYFP); + public static final /*float*/ Binary HYPOT = binary("HYPOT", "hypot", VectorSupport.VECTOR_OP_HYPOT, VO_ONLYFP | VO_SPECIAL | VO_MATHLIB); // Ternary operators @@ -1373,7 +1376,7 @@ public T find(OP op, int opc, IntFunction supplier) { if (fn != null) return fn; fn = supplier.apply(opc); if (fn == null) throw badOp(op); - assert(VectorSupport.isNonCapturingLambda(fn)) : fn; + assert(isNonCapturingLambda(fn)) : fn; // The JIT can see into this cache: cache[opc] = fn; return fn; diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index 8084cc307e8..6d9db65a1ba 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -712,10 +712,15 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { return blend(broadcast(-1), compare(NE, 0)); } #if[BITWISE] - if (op == NOT) { + else if (op == NOT) { return broadcast(-1).lanewise(XOR, this); } #end[BITWISE] +#if[FP] + else if (opKind(op, VO_MATHLIB)) { + return unaryMathOp(op); + } +#end[FP] } int opc = opCode(op); return VectorSupport.unaryOp( @@ -742,10 +747,15 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { return blend(broadcast(-1), compare(NE, 0, m)); } #if[BITWISE] - if (op == NOT) { + else if (op == NOT) { return lanewise(XOR, broadcast(-1), m); } #end[BITWISE] +#if[FP] + else if (opKind(op, VO_MATHLIB)) { + return blend(unaryMathOp(op), m); + } +#end[FP] } int opc = opCode(op); return VectorSupport.unaryOp( @@ -754,6 +764,15 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { UN_IMPL.find(op, opc, $abstractvectortype$::unaryOperations)); } +#if[FP] + @ForceInline + final + $abstractvectortype$ unaryMathOp(VectorOperators.Unary op) { + return VectorMathLibrary.unaryMathOp(op, opCode(op), species(), $abstractvectortype$::unaryOperations, + this); + } +#end[FP] + private static final ImplCache>> UN_IMPL = new ImplCache<>(Unary.class, $Type$Vector.class); @@ -856,6 +875,11 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { = this{#if[FP]?.viewAsIntegralLanes()}.compare(EQ, ($bitstype$) 0); return this.blend(that, mask{#if[FP]?.cast(vspecies())}); } +#if[FP] + else if (opKind(op, VO_MATHLIB)) { + return binaryMathOp(op, that); + } +#end[FP] #if[BITWISE] #if[!FP] if (opKind(op, VO_SHIFT)) { @@ -915,6 +939,12 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { return this.blend(that, mask); #end[FP] } +#if[FP] + else if (opKind(op, VO_MATHLIB)) { + return this.blend(binaryMathOp(op, that), m); + } +#end[FP] + #if[BITWISE] #if[!FP] if (opKind(op, VO_SHIFT)) { @@ -945,6 +975,15 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { BIN_IMPL.find(op, opc, $abstractvectortype$::binaryOperations)); } +#if[FP] + @ForceInline + final + $abstractvectortype$ binaryMathOp(VectorOperators.Binary op, $abstractvectortype$ that) { + return VectorMathLibrary.binaryMathOp(op, opCode(op), species(), $abstractvectortype$::binaryOperations, + this, that); + } +#end[FP] + private static final ImplCache>> BIN_IMPL = new ImplCache<>(Binary.class, $Type$Vector.class); From 91a9043f9df0e345719df3bfd0a7d0f2a96e6109 Mon Sep 17 00:00:00 2001 From: Anjian-Wen Date: Sat, 26 Apr 2025 02:58:51 +0000 Subject: [PATCH 040/118] 8355562: RISC-V: Cleanup names of vector-scalar instructions in riscv_v.ad Reviewed-by: fyang, fjiang --- src/hotspot/cpu/riscv/riscv_v.ad | 292 +++++++++++++++---------------- 1 file changed, 146 insertions(+), 146 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 7df3c857a4d..d0f31a82069 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -415,11 +415,11 @@ instruct vadd_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate add (unpredicated) -instruct vadd_immI(vReg dst, vReg src1, immI5 con) %{ +instruct vaddI_vi(vReg dst, vReg src1, immI5 con) %{ match(Set dst (AddVB src1 (Replicate con))); match(Set dst (AddVS src1 (Replicate con))); match(Set dst (AddVI src1 (Replicate con))); - format %{ "vadd_immI $dst, $src1, $con" %} + format %{ "vaddI_vi $dst, $src1, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -430,9 +430,9 @@ instruct vadd_immI(vReg dst, vReg src1, immI5 con) %{ ins_pipe(pipe_slow); %} -instruct vadd_immL(vReg dst, vReg src1, immL5 con) %{ +instruct vaddL_vi(vReg dst, vReg src1, immL5 con) %{ match(Set dst (AddVL src1 (Replicate con))); - format %{ "vadd_immL $dst, $src1, $con" %} + format %{ "vaddL_vi $dst, $src1, $con" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vadd_vi(as_VectorRegister($dst$$reg), @@ -444,11 +444,11 @@ instruct vadd_immL(vReg dst, vReg src1, immL5 con) %{ // vector-scalar add (unpredicated) -instruct vadd_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ +instruct vaddI_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ match(Set dst (AddVB src1 (Replicate src2))); match(Set dst (AddVS src1 (Replicate src2))); match(Set dst (AddVI src1 (Replicate src2))); - format %{ "vadd_regI $dst, $src1, $src2" %} + format %{ "vaddI_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -459,9 +459,9 @@ instruct vadd_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ ins_pipe(pipe_slow); %} -instruct vadd_regL(vReg dst, vReg src1, iRegL src2) %{ +instruct vaddL_vx(vReg dst, vReg src1, iRegL src2) %{ match(Set dst (AddVL src1 (Replicate src2))); - format %{ "vadd_regL $dst, $src1, $src2" %} + format %{ "vaddL_vx $dst, $src1, $src2" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vadd_vx(as_VectorRegister($dst$$reg), @@ -473,11 +473,11 @@ instruct vadd_regL(vReg dst, vReg src1, iRegL src2) %{ // vector-immediate add (predicated) -instruct vadd_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ +instruct vaddI_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ match(Set dst_src (AddVB (Binary dst_src (Replicate con)) v0)); match(Set dst_src (AddVS (Binary dst_src (Replicate con)) v0)); match(Set dst_src (AddVI (Binary dst_src (Replicate con)) v0)); - format %{ "vadd_immI_masked $dst_src, $dst_src, $con" %} + format %{ "vaddI_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -488,9 +488,9 @@ instruct vadd_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vadd_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ +instruct vaddL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ match(Set dst_src (AddVL (Binary dst_src (Replicate con)) v0)); - format %{ "vadd_immL_masked $dst_src, $dst_src, $con" %} + format %{ "vaddL_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vadd_vi(as_VectorRegister($dst_src$$reg), @@ -502,11 +502,11 @@ instruct vadd_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar add (predicated) -instruct vadd_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ +instruct vaddI_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ match(Set dst_src (AddVB (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (AddVS (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (AddVI (Binary dst_src (Replicate src2)) v0)); - format %{ "vadd_regI_masked $dst_src, $dst_src, $src2" %} + format %{ "vaddI_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -517,9 +517,9 @@ instruct vadd_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vadd_regL_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ +instruct vaddL_vx_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ match(Set dst_src (AddVL (Binary dst_src (Replicate src2)) v0)); - format %{ "vadd_regL_masked $dst_src, $dst_src, $src2" %} + format %{ "vaddL_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vadd_vx(as_VectorRegister($dst_src$$reg), @@ -595,11 +595,11 @@ instruct vsub_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-scalar sub (unpredicated) -instruct vsub_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ +instruct vsubI_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ match(Set dst (SubVB src1 (Replicate src2))); match(Set dst (SubVS src1 (Replicate src2))); match(Set dst (SubVI src1 (Replicate src2))); - format %{ "vsub_regI $dst, $src1, $src2" %} + format %{ "vsubI_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -610,9 +610,9 @@ instruct vsub_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ ins_pipe(pipe_slow); %} -instruct vsub_regL(vReg dst, vReg src1, iRegL src2) %{ +instruct vsubL_vx(vReg dst, vReg src1, iRegL src2) %{ match(Set dst (SubVL src1 (Replicate src2))); - format %{ "vsub_regL $dst, $src1, $src2" %} + format %{ "vsubL_vx $dst, $src1, $src2" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vsub_vx(as_VectorRegister($dst$$reg), @@ -624,11 +624,11 @@ instruct vsub_regL(vReg dst, vReg src1, iRegL src2) %{ // vector-scalar sub (predicated) -instruct vsub_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ +instruct vsubI_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ match(Set dst_src (SubVB (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (SubVS (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (SubVI (Binary dst_src (Replicate src2)) v0)); - format %{ "vsub_regI_masked $dst_src, $dst_src, $src2" %} + format %{ "vsubI_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -639,9 +639,9 @@ instruct vsub_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vsub_regL_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ +instruct vsubL_vx_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ match(Set dst_src (SubVL (Binary dst_src (Replicate src2)) v0)); - format %{ "vsub_regL_masked $dst_src, $dst_src, $src2" %} + format %{ "vsub_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vsub_vx(as_VectorRegister($dst_src$$reg), @@ -685,12 +685,12 @@ instruct vand_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate and (unpredicated) -instruct vand_immI(vReg dst_src, immI5 con) %{ +instruct vandI_vi(vReg dst_src, immI5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (AndV dst_src (Replicate con))); - format %{ "vand_immI $dst_src, $dst_src, $con" %} + format %{ "vandI_vi $dst_src, $dst_src, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -701,10 +701,10 @@ instruct vand_immI(vReg dst_src, immI5 con) %{ ins_pipe(pipe_slow); %} -instruct vand_immL(vReg dst_src, immL5 con) %{ +instruct vandL_vi(vReg dst_src, immL5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (AndV dst_src (Replicate con))); - format %{ "vand_immL $dst_src, $dst_src, $con" %} + format %{ "vandL_vi $dst_src, $dst_src, $con" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vand_vi(as_VectorRegister($dst_src$$reg), @@ -716,12 +716,12 @@ instruct vand_immL(vReg dst_src, immL5 con) %{ // vector-scalar and (unpredicated) -instruct vand_regI(vReg dst_src, iRegIorL2I src) %{ +instruct vandI_vx(vReg dst_src, iRegIorL2I src) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (AndV dst_src (Replicate src))); - format %{ "vand_regI $dst_src, $dst_src, $src" %} + format %{ "vandI_vx $dst_src, $dst_src, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -732,10 +732,10 @@ instruct vand_regI(vReg dst_src, iRegIorL2I src) %{ ins_pipe(pipe_slow); %} -instruct vand_regL(vReg dst_src, iRegL src) %{ +instruct vandL_vx(vReg dst_src, iRegL src) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (AndV dst_src (Replicate src))); - format %{ "vand_regL $dst_src, $dst_src, $src" %} + format %{ "vandL_vx $dst_src, $dst_src, $src" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vand_vx(as_VectorRegister($dst_src$$reg), @@ -747,12 +747,12 @@ instruct vand_regL(vReg dst_src, iRegL src) %{ // vector-immediate and (predicated) -instruct vand_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ +instruct vandI_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (AndV (Binary dst_src (Replicate con)) v0)); - format %{ "vand_immI_masked $dst_src, $dst_src, $con" %} + format %{ "vandI_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -763,10 +763,10 @@ instruct vand_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vand_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ +instruct vandL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (AndV (Binary dst_src (Replicate con)) v0)); - format %{ "vand_immL_masked $dst_src, $dst_src, $con" %} + format %{ "vandL_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vand_vi(as_VectorRegister($dst_src$$reg), @@ -778,12 +778,12 @@ instruct vand_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar and (predicated) -instruct vand_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ +instruct vandI_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (AndV (Binary dst_src (Replicate src)) v0)); - format %{ "vand_regI_masked $dst_src, $dst_src, $src" %} + format %{ "vandI_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -794,10 +794,10 @@ instruct vand_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vand_regL_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ +instruct vandL_vx_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (AndV (Binary dst_src (Replicate src)) v0)); - format %{ "vand_regL_masked $dst_src, $dst_src, $src" %} + format %{ "vandL_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vand_vx(as_VectorRegister($dst_src$$reg), @@ -841,12 +841,12 @@ instruct vor_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate or (unpredicated) -instruct vor_immI(vReg dst_src, immI5 con) %{ +instruct vorI_vi(vReg dst_src, immI5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (OrV dst_src (Replicate con))); - format %{ "vor_immI $dst_src, $dst_src, $con" %} + format %{ "vorI_vi $dst_src, $dst_src, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -857,10 +857,10 @@ instruct vor_immI(vReg dst_src, immI5 con) %{ ins_pipe(pipe_slow); %} -instruct vor_immL(vReg dst_src, immL5 con) %{ +instruct vorL_vi(vReg dst_src, immL5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (OrV dst_src (Replicate con))); - format %{ "vor_immL $dst_src, $dst_src, $con" %} + format %{ "vorL_vi $dst_src, $dst_src, $con" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vor_vi(as_VectorRegister($dst_src$$reg), @@ -872,12 +872,12 @@ instruct vor_immL(vReg dst_src, immL5 con) %{ // vector-scalar or (unpredicated) -instruct vor_regI(vReg dst_src, iRegIorL2I src) %{ +instruct vorI_vx(vReg dst_src, iRegIorL2I src) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (OrV dst_src (Replicate src))); - format %{ "vor_regI $dst_src, $dst_src, $src" %} + format %{ "vorI_vx $dst_src, $dst_src, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -888,10 +888,10 @@ instruct vor_regI(vReg dst_src, iRegIorL2I src) %{ ins_pipe(pipe_slow); %} -instruct vor_regL(vReg dst_src, iRegL src) %{ +instruct vorL_vx(vReg dst_src, iRegL src) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (OrV dst_src (Replicate src))); - format %{ "vor_regL $dst_src, $dst_src, $src" %} + format %{ "vorL_vx $dst_src, $dst_src, $src" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vor_vx(as_VectorRegister($dst_src$$reg), @@ -903,12 +903,12 @@ instruct vor_regL(vReg dst_src, iRegL src) %{ // vector-immediate or (predicated) -instruct vor_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ +instruct vorI_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (OrV (Binary dst_src (Replicate con)) v0)); - format %{ "vor_immI_masked $dst_src, $dst_src, $con" %} + format %{ "vorI_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -919,10 +919,10 @@ instruct vor_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vor_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ +instruct vorL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (OrV (Binary dst_src (Replicate con)) v0)); - format %{ "vor_immL_masked $dst_src, $dst_src, $con" %} + format %{ "vorL_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vor_vi(as_VectorRegister($dst_src$$reg), @@ -934,12 +934,12 @@ instruct vor_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar or (predicated) -instruct vor_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ +instruct vorI_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (OrV (Binary dst_src (Replicate src)) v0)); - format %{ "vor_regI_masked $dst_src, $dst_src, $src" %} + format %{ "vorI_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -950,10 +950,10 @@ instruct vor_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vor_regL_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ +instruct vorL_vx_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (OrV (Binary dst_src (Replicate src)) v0)); - format %{ "vor_regL_masked $dst_src, $dst_src, $src" %} + format %{ "vorL_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vor_vx(as_VectorRegister($dst_src$$reg), @@ -997,12 +997,12 @@ instruct vxor_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate xor (unpredicated) -instruct vxor_immI(vReg dst_src, immI5 con) %{ +instruct vxorI_vi(vReg dst_src, immI5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (XorV dst_src (Replicate con))); - format %{ "vxor_immI $dst_src, $dst_src, $con" %} + format %{ "vxorI_vi $dst_src, $dst_src, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1013,10 +1013,10 @@ instruct vxor_immI(vReg dst_src, immI5 con) %{ ins_pipe(pipe_slow); %} -instruct vxor_immL(vReg dst_src, immL5 con) %{ +instruct vxorL_vi(vReg dst_src, immL5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (XorV dst_src (Replicate con))); - format %{ "vxor_immL $dst_src, $dst_src, $con" %} + format %{ "vxorL_vi $dst_src, $dst_src, $con" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vxor_vi(as_VectorRegister($dst_src$$reg), @@ -1028,12 +1028,12 @@ instruct vxor_immL(vReg dst_src, immL5 con) %{ // vector-scalar xor (unpredicated) -instruct vxor_regI(vReg dst_src, iRegIorL2I src) %{ +instruct vxorI_vx(vReg dst_src, iRegIorL2I src) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (XorV dst_src (Replicate src))); - format %{ "vxor_regI $dst_src, $dst_src, $src" %} + format %{ "vxorI_vx $dst_src, $dst_src, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1044,10 +1044,10 @@ instruct vxor_regI(vReg dst_src, iRegIorL2I src) %{ ins_pipe(pipe_slow); %} -instruct vxor_regL(vReg dst_src, iRegL src) %{ +instruct vxorL_vx(vReg dst_src, iRegL src) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (XorV dst_src (Replicate src))); - format %{ "vxor_regL $dst_src, $dst_src, $src" %} + format %{ "vxorL_vx $dst_src, $dst_src, $src" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vxor_vx(as_VectorRegister($dst_src$$reg), @@ -1059,12 +1059,12 @@ instruct vxor_regL(vReg dst_src, iRegL src) %{ // vector-immediate xor (predicated) -instruct vxor_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ +instruct vxorI_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (XorV (Binary dst_src (Replicate con)) v0)); - format %{ "vxor_immI_masked $dst_src, $dst_src, $con" %} + format %{ "vxorI_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1075,10 +1075,10 @@ instruct vxor_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vxor_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ +instruct vxorL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (XorV (Binary dst_src (Replicate con)) v0)); - format %{ "vxor_immL_masked $dst_src, $dst_src, $con" %} + format %{ "vxorL_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vxor_vi(as_VectorRegister($dst_src$$reg), @@ -1090,12 +1090,12 @@ instruct vxor_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar xor (predicated) -instruct vxor_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ +instruct vxorI_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (XorV (Binary dst_src (Replicate src)) v0)); - format %{ "vxor_regI_masked $dst_src, $dst_src, $src" %} + format %{ "vxorI_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1106,10 +1106,10 @@ instruct vxor_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vxor_regL_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ +instruct vxorL_vx_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (XorV (Binary dst_src (Replicate src)) v0)); - format %{ "vxor_regL_masked $dst_src, $dst_src, $src" %} + format %{ "vxorL_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vxor_vx(as_VectorRegister($dst_src$$reg), @@ -1801,11 +1801,11 @@ instruct vmul_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-scalar mul (unpredicated) -instruct vmul_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ +instruct vmulI_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ match(Set dst (MulVB src1 (Replicate src2))); match(Set dst (MulVS src1 (Replicate src2))); match(Set dst (MulVI src1 (Replicate src2))); - format %{ "vmul_regI $dst, $src1, $src2" %} + format %{ "vmulI_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1816,9 +1816,9 @@ instruct vmul_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ ins_pipe(pipe_slow); %} -instruct vmul_regL(vReg dst, vReg src1, iRegL src2) %{ +instruct vmulL_vx(vReg dst, vReg src1, iRegL src2) %{ match(Set dst (MulVL src1 (Replicate src2))); - format %{ "vmul_regL $dst, $src1, $src2" %} + format %{ "vmulL_vx $dst, $src1, $src2" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vmul_vx(as_VectorRegister($dst$$reg), @@ -1830,11 +1830,11 @@ instruct vmul_regL(vReg dst, vReg src1, iRegL src2) %{ // vector-scalar mul (predicated) -instruct vmul_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ +instruct vmulI_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ match(Set dst_src (MulVB (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (MulVS (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (MulVI (Binary dst_src (Replicate src2)) v0)); - format %{ "vmul_regI_masked $dst_src, $dst_src, $src2" %} + format %{ "vmulI_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1845,9 +1845,9 @@ instruct vmul_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vmul_regL_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ +instruct vmulL_vx_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ match(Set dst_src (MulVL (Binary dst_src (Replicate src2)) v0)); - format %{ "vmul_regL_masked $dst_src, $dst_src, $src2" %} + format %{ "vmulL_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vmul_vx(as_VectorRegister($dst_src$$reg), @@ -3122,10 +3122,10 @@ instruct vlsrL_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vasrB_imm(vReg dst, vReg src, immI shift) %{ +instruct vasrB_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (RShiftVB src (RShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vasrB_imm $dst, $src, $shift" %} + format %{ "vasrB_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); @@ -3140,10 +3140,10 @@ instruct vasrB_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vasrS_imm(vReg dst, vReg src, immI shift) %{ +instruct vasrS_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (RShiftVS src (RShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vasrS_imm $dst, $src, $shift" %} + format %{ "vasrS_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); @@ -3158,10 +3158,10 @@ instruct vasrS_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vasrI_imm(vReg dst, vReg src, immI shift) %{ +instruct vasrI_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (RShiftVI src (RShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vasrI_imm $dst, $src, $shift" %} + format %{ "vasrI_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_INT, Matcher::vector_length(this)); @@ -3175,11 +3175,11 @@ instruct vasrI_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vasrL_imm(vReg dst, vReg src, immI shift) %{ +instruct vasrL_vi(vReg dst, vReg src, immI shift) %{ predicate((n->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst (RShiftVL src (RShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vasrL_imm $dst, $src, $shift" %} + format %{ "vasrL_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -3193,10 +3193,10 @@ instruct vasrL_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vasrB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vasrB_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (RShiftVB (Binary dst_src (RShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vasrB_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vasrB_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3210,10 +3210,10 @@ instruct vasrB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vasrS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vasrS_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (RShiftVS (Binary dst_src (RShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vasrS_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vasrS_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3227,10 +3227,10 @@ instruct vasrS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vasrI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vasrI_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (RShiftVI (Binary dst_src (RShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vasrI_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vasrI_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3243,11 +3243,11 @@ instruct vasrI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vasrL_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vasrL_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ predicate((n->in(1)->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst_src (RShiftVL (Binary dst_src (RShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vasrL_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vasrL_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3260,10 +3260,10 @@ instruct vasrL_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlsrB_imm(vReg dst, vReg src, immI shift) %{ +instruct vlsrB_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (URShiftVB src (RShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vlsrB_imm $dst, $src, $shift" %} + format %{ "vlsrB_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); @@ -3282,10 +3282,10 @@ instruct vlsrB_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlsrS_imm(vReg dst, vReg src, immI shift) %{ +instruct vlsrS_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (URShiftVS src (RShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vlsrS_imm $dst, $src, $shift" %} + format %{ "vlsrS_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); @@ -3304,10 +3304,10 @@ instruct vlsrS_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlsrI_imm(vReg dst, vReg src, immI shift) %{ +instruct vlsrI_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (URShiftVI src (RShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vlsrI_imm $dst, $src, $shift" %} + format %{ "vlsrI_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_INT, Matcher::vector_length(this)); @@ -3321,11 +3321,11 @@ instruct vlsrI_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlsrL_imm(vReg dst, vReg src, immI shift) %{ +instruct vlsrL_vi(vReg dst, vReg src, immI shift) %{ predicate((n->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst (URShiftVL src (RShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vlsrL_imm $dst, $src, $shift" %} + format %{ "vlsrL_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -3339,10 +3339,10 @@ instruct vlsrL_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlsrB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlsrB_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (URShiftVB (Binary dst_src (RShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vlsrB_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlsrB_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3360,10 +3360,10 @@ instruct vlsrB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlsrS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlsrS_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (URShiftVS (Binary dst_src (RShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vlsrS_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlsrS_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3381,10 +3381,10 @@ instruct vlsrS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlsrI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlsrI_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (URShiftVI (Binary dst_src (RShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vlsrI_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlsrI_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3397,11 +3397,11 @@ instruct vlsrI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlsrL_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlsrL_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ predicate((n->in(1)->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst_src (URShiftVL (Binary dst_src (RShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vlsrL_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlsrL_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3414,10 +3414,10 @@ instruct vlsrL_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlslB_imm(vReg dst, vReg src, immI shift) %{ +instruct vlslB_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (LShiftVB src (LShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vlslB_imm $dst, $src, $shift" %} + format %{ "vlslB_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); @@ -3431,10 +3431,10 @@ instruct vlslB_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlslS_imm(vReg dst, vReg src, immI shift) %{ +instruct vlslS_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (LShiftVS src (LShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vlslS_imm $dst, $src, $shift" %} + format %{ "vlslS_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); @@ -3448,10 +3448,10 @@ instruct vlslS_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlslI_imm(vReg dst, vReg src, immI shift) %{ +instruct vlslI_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (LShiftVI src (LShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vlslI_imm $dst, $src, $shift" %} + format %{ "vlslI_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_INT, Matcher::vector_length(this)); @@ -3460,11 +3460,11 @@ instruct vlslI_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlslL_imm(vReg dst, vReg src, immI shift) %{ +instruct vlslL_vi(vReg dst, vReg src, immI shift) %{ predicate((n->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst (LShiftVL src (LShiftCntV shift))); ins_cost(VEC_COST); - format %{ "vlslL_imm $dst, $src, $shift" %} + format %{ "vlslL_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -3473,10 +3473,10 @@ instruct vlslL_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlslB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlslB_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (LShiftVB (Binary dst_src (LShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vlslB_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlslB_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); @@ -3491,10 +3491,10 @@ instruct vlslB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlslS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlslS_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (LShiftVS (Binary dst_src (LShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vlslS_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlslS_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); @@ -3509,10 +3509,10 @@ instruct vlslS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlslI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlslI_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (LShiftVI (Binary dst_src (LShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vlslI_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlslI_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_INT, Matcher::vector_length(this)); @@ -3522,11 +3522,11 @@ instruct vlslI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlslL_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlslL_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ predicate((n->in(1)->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst_src (LShiftVL (Binary dst_src (LShiftCntV shift)) v0)); ins_cost(VEC_COST); - format %{ "vlslL_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlslL_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -3566,9 +3566,9 @@ instruct vrotate_right(vReg dst, vReg src, vReg shift) %{ %} // Only the low log2(SEW) bits of shift value are used, all other bits are ignored. -instruct vrotate_right_reg(vReg dst, vReg src, iRegIorL2I shift) %{ +instruct vrotate_right_vx(vReg dst, vReg src, iRegIorL2I shift) %{ match(Set dst (RotateRightV src (Replicate shift))); - format %{ "vrotate_right_reg $dst, $src, $shift\t" %} + format %{ "vrotate_right_vx $dst, $src, $shift\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3578,9 +3578,9 @@ instruct vrotate_right_reg(vReg dst, vReg src, iRegIorL2I shift) %{ ins_pipe(pipe_slow); %} -instruct vrotate_right_imm(vReg dst, vReg src, immI shift) %{ +instruct vrotate_right_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (RotateRightV src shift)); - format %{ "vrotate_right_imm $dst, $src, $shift\t" %} + format %{ "vrotate_right_vi $dst, $src, $shift\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); uint32_t bits = type2aelembytes(bt) * 8; @@ -3598,7 +3598,7 @@ instruct vrotate_right_imm(vReg dst, vReg src, immI shift) %{ instruct vrotate_right_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateRightV (Binary dst_src shift) v0)); - format %{ "vrotate_right_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_right_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3609,9 +3609,9 @@ instruct vrotate_right_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ %} // Only the low log2(SEW) bits of shift value are used, all other bits are ignored. -instruct vrotate_right_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ +instruct vrotate_right_vx_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateRightV (Binary dst_src (Replicate shift)) v0)); - format %{ "vrotate_right_reg_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_right_vx_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3621,9 +3621,9 @@ instruct vrotate_right_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0 ins_pipe(pipe_slow); %} -instruct vrotate_right_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vrotate_right_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateRightV (Binary dst_src shift) v0)); - format %{ "vrotate_right_imm_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_right_vi_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); uint32_t bits = type2aelembytes(bt) * 8; @@ -3653,9 +3653,9 @@ instruct vrotate_left(vReg dst, vReg src, vReg shift) %{ %} // Only the low log2(SEW) bits of shift value are used, all other bits are ignored. -instruct vrotate_left_reg(vReg dst, vReg src, iRegIorL2I shift) %{ +instruct vrotate_left_vx(vReg dst, vReg src, iRegIorL2I shift) %{ match(Set dst (RotateLeftV src (Replicate shift))); - format %{ "vrotate_left_reg $dst, $src, $shift\t" %} + format %{ "vrotate_left_vx $dst, $src, $shift\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3665,9 +3665,9 @@ instruct vrotate_left_reg(vReg dst, vReg src, iRegIorL2I shift) %{ ins_pipe(pipe_slow); %} -instruct vrotate_left_imm(vReg dst, vReg src, immI shift) %{ +instruct vrotate_left_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (RotateLeftV src shift)); - format %{ "vrotate_left_imm $dst, $src, $shift\t" %} + format %{ "vrotate_left_vi $dst, $src, $shift\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); uint32_t bits = type2aelembytes(bt) * 8; @@ -3686,7 +3686,7 @@ instruct vrotate_left_imm(vReg dst, vReg src, immI shift) %{ instruct vrotate_left_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateLeftV (Binary dst_src shift) v0)); - format %{ "vrotate_left_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_left_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3697,9 +3697,9 @@ instruct vrotate_left_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ %} // Only the low log2(SEW) bits of shift value are used, all other bits are ignored. -instruct vrotate_left_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ +instruct vrotate_left_vx_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateLeftV (Binary dst_src (Replicate shift)) v0)); - format %{ "vrotate_left_reg_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_left_vx_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3709,9 +3709,9 @@ instruct vrotate_left_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) ins_pipe(pipe_slow); %} -instruct vrotate_left_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vrotate_left_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateLeftV (Binary dst_src shift) v0)); - format %{ "vrotate_left_imm_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_left_vi_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); uint32_t bits = type2aelembytes(bt) * 8; From 3b3a055d7605338e93814ccfe2a4a18a7786f43f Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Sat, 26 Apr 2025 03:31:21 +0000 Subject: [PATCH 041/118] 8342676: Unsigned Vector Min / Max transforms Reviewed-by: sviswanathan, epeter --- src/hotspot/share/opto/vectornode.cpp | 66 +++ src/hotspot/share/opto/vectornode.hpp | 5 + .../compiler/lib/ir_framework/IRNode.java | 40 ++ .../VectorCommutativeOperSharingTest.java | 50 ++ .../VectorUnsignedMinMaxOperationsTest.java | 472 ++++++++++++++++++ 5 files changed, 633 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 084b70a6906..05ef64af704 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -2237,6 +2237,72 @@ bool MulVLNode::has_uint_inputs() const { has_vector_elements_fit_uint(in(2)); } +static Node* UMinMaxV_Ideal(Node* n, PhaseGVN* phase, bool can_reshape) { + int vopc = n->Opcode(); + assert(vopc == Op_UMinV || vopc == Op_UMaxV, "Unexpected opcode"); + + Node* umin = nullptr; + Node* umax = nullptr; + int lopc = n->in(1)->Opcode(); + int ropc = n->in(2)->Opcode(); + + if (lopc == Op_UMinV && ropc == Op_UMaxV) { + umin = n->in(1); + umax = n->in(2); + } else if (lopc == Op_UMaxV && ropc == Op_UMinV) { + umin = n->in(2); + umax = n->in(1); + } else { + return nullptr; + } + + // UMin (UMin(a, b), UMax(a, b)) => UMin(a, b) + // UMin (UMax(a, b), UMin(b, a)) => UMin(a, b) + // UMax (UMin(a, b), UMax(a, b)) => UMax(a, b) + // UMax (UMax(a, b), UMin(b, a)) => UMax(a, b) + if (umin != nullptr && umax != nullptr) { + if ((umin->in(1) == umax->in(1) && umin->in(2) == umax->in(2)) || + (umin->in(2) == umax->in(1) && umin->in(1) == umax->in(2))) { + if (vopc == Op_UMinV) { + return new UMinVNode(umax->in(1), umax->in(2), n->bottom_type()->is_vect()); + } else { + return new UMaxVNode(umax->in(1), umax->in(2), n->bottom_type()->is_vect()); + } + } + } + + return nullptr; +} + +Node* UMinVNode::Ideal(PhaseGVN* phase, bool can_reshape) { + Node* progress = UMinMaxV_Ideal(this, phase, can_reshape); + if (progress != nullptr) return progress; + + return VectorNode::Ideal(phase, can_reshape); +} + +Node* UMinVNode::Identity(PhaseGVN* phase) { + // UMin (a, a) => a + if (in(1) == in(2)) { + return in(1); + } + return this; +} + +Node* UMaxVNode::Ideal(PhaseGVN* phase, bool can_reshape) { + Node* progress = UMinMaxV_Ideal(this, phase, can_reshape); + if (progress != nullptr) return progress; + + return VectorNode::Ideal(phase, can_reshape); +} + +Node* UMaxVNode::Identity(PhaseGVN* phase) { + // UMax (a, a) => a + if (in(1) == in(2)) { + return in(1); + } + return this; +} #ifndef PRODUCT void VectorBoxAllocateNode::dump_spec(outputStream *st) const { CallStaticJavaNode::dump_spec(st); diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index ae817598d39..e72c3880c79 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -675,9 +675,12 @@ class UMinVNode : public VectorNode { UMinVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2 ,vt) { assert(is_integral_type(vt->element_basic_type()), ""); } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + virtual Node* Identity(PhaseGVN* phase); virtual int Opcode() const; }; + //------------------------------MaxVNode-------------------------------------- // Vector Max class MaxVNode : public VectorNode { @@ -691,6 +694,8 @@ class UMaxVNode : public VectorNode { UMaxVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) { assert(is_integral_type(vt->element_basic_type()), ""); } + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + virtual Node* Identity(PhaseGVN* phase); virtual int Opcode() const; }; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 5dabcf0f828..ebcbd9fbbc7 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1333,6 +1333,46 @@ public class IRNode { vectorNode(MUL_ADD_VS2VI, "MulAddVS2VI", TYPE_INT); } + public static final String UMIN_VB = VECTOR_PREFIX + "UMIN_VB" + POSTFIX; + static { + vectorNode(UMIN_VB, "UMinV", TYPE_BYTE); + } + + public static final String UMIN_VS = VECTOR_PREFIX + "UMIN_VS" + POSTFIX; + static { + vectorNode(UMIN_VS, "UMinV", TYPE_SHORT); + } + + public static final String UMIN_VI = VECTOR_PREFIX + "UMIN_VI" + POSTFIX; + static { + vectorNode(UMIN_VI, "UMinV", TYPE_INT); + } + + public static final String UMIN_VL = VECTOR_PREFIX + "UMIN_VL" + POSTFIX; + static { + vectorNode(UMIN_VL, "UMinV", TYPE_LONG); + } + + public static final String UMAX_VB = VECTOR_PREFIX + "UMAX_VB" + POSTFIX; + static { + vectorNode(UMAX_VB, "UMaxV", TYPE_BYTE); + } + + public static final String UMAX_VS = VECTOR_PREFIX + "UMAX_VS" + POSTFIX; + static { + vectorNode(UMAX_VS, "UMaxV", TYPE_SHORT); + } + + public static final String UMAX_VI = VECTOR_PREFIX + "UMAX_VI" + POSTFIX; + static { + vectorNode(UMAX_VI, "UMaxV", TYPE_INT); + } + + public static final String UMAX_VL = VECTOR_PREFIX + "UMAX_VL" + POSTFIX; + static { + vectorNode(UMAX_VL, "UMaxV", TYPE_LONG); + } + // Can only be used if avx512_vnni is available. public static final String MUL_ADD_VS2VI_VNNI = PREFIX + "MUL_ADD_VS2VI_VNNI" + POSTFIX; static { diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java index c2237000e6f..73718193109 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java @@ -573,4 +573,54 @@ public void checkVectorIRSharing19() { Verify.checkEQ(ir1[i], (mask ? ia[i] + ib[i] : ia[i]) + (mask ? ib[i] + ia[i] : ib[i])); } } + + @Test + @IR(counts = {IRNode.UMAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 "}, applyIfCPUFeatureOr = {"avx", "true"}) + public void testVectorIRSharing20(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // UMax ((UMax vec1, vec2), (UMax vec2, vec1)) + vec1.lanewise(VectorOperators.UMAX, vec2) + .lanewise(VectorOperators.UMAX, vec2.lanewise(VectorOperators.UMAX, vec1)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing20") + public void testVectorIRSharingDriver20() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing20(i); + } + checkVectorIRSharing20(); + } + + public void checkVectorIRSharing20() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], VectorMath.maxUnsigned(ia[i], ib[i])); + } + } + + @Test + @IR(counts = {IRNode.UMIN_VI, IRNode.VECTOR_SIZE_ANY, " 1 "}, applyIfCPUFeatureOr = {"avx", "true"}) + public void testVectorIRSharing21(int index) { + IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index); + IntVector vec2 = IntVector.fromArray(I_SPECIES, ib, index); + // UMin ((UMin vec1, vec2), (UMin vec2, vec1)) + vec1.lanewise(VectorOperators.UMIN, vec2) + .lanewise(VectorOperators.UMIN, vec2.lanewise(VectorOperators.UMIN, vec1)) + .intoArray(ir1, index); + } + + @Run(test = "testVectorIRSharing21") + public void testVectorIRSharingDriver21() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) { + testVectorIRSharing21(i); + } + checkVectorIRSharing21(); + } + + public void checkVectorIRSharing21() { + for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) { + Verify.checkEQ(ir1[i], VectorMath.minUnsigned(ia[i], ib[i])); + } + } } diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java new file mode 100644 index 00000000000..d94d65c5143 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** +* @test +* @bug 8342676 +* @summary Unsigned Vector Min / Max transforms +* @modules jdk.incubator.vector +* @library /test/lib / +* @run driver compiler.vectorapi.VectorUnsignedMinMaxOperationsTest +*/ + +package compiler.vectorapi; + +import jdk.incubator.vector.*; +import compiler.lib.ir_framework.*; +import java.util.stream.IntStream; + +public class VectorUnsignedMinMaxOperationsTest { + private static final int COUNT = 2048; + private static final VectorSpecies lspec = LongVector.SPECIES_PREFERRED; + private static final VectorSpecies ispec = IntVector.SPECIES_PREFERRED; + private static final VectorSpecies sspec = ShortVector.SPECIES_PREFERRED; + private static final VectorSpecies bspec = ByteVector.SPECIES_PREFERRED; + + private long[] long_in1; + private int[] int_in1; + private short[] short_in1; + private byte[] byte_in1; + + private long[] long_in2; + private int[] int_in2; + private short[] short_in2; + private byte[] byte_in2; + + private long[] long_out; + private int[] int_out; + private short[] short_out; + private byte[] byte_out; + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(5000) + .addFlags("--add-modules=jdk.incubator.vector") + .start(); + } + + public VectorUnsignedMinMaxOperationsTest() { + byte_in1 = new byte[COUNT]; + short_in1 = new short[COUNT]; + int_in1 = new int[COUNT]; + long_in1 = new long[COUNT]; + + byte_in2 = new byte[COUNT]; + short_in2 = new short[COUNT]; + int_in2 = new int[COUNT]; + long_in2 = new long[COUNT]; + IntStream.range(0, COUNT).forEach( + i -> { + if ((i & 1) == 0) { + long_in1[i] = Long.MAX_VALUE; + long_in2[i] = i; + int_in1[i] = Integer.MAX_VALUE; + int_in2[i] = i; + short_in1[i] = Short.MAX_VALUE; + short_in2[i] = (short)i; + byte_in1[i] = Byte.MAX_VALUE; + byte_in2[i] = (byte)i; + } else { + long_in1[i] = Long.MIN_VALUE; + long_in2[i] = -i; + int_in1[i] = Integer.MIN_VALUE; + int_in2[i] = -i; + short_in1[i] = Short.MIN_VALUE; + short_in2[i] = (short)-i; + byte_in1[i] = Byte.MIN_VALUE; + byte_in2[i] = (byte)-i; + } + } + ); + long_out = new long[COUNT]; + int_out = new int[COUNT]; + short_out = new short[COUNT]; + byte_out = new byte[COUNT]; + } + + @Test + @IR(counts = {IRNode.UMAX_VB, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umax_byte() { + for (int i = 0; i < COUNT; i += bspec.length()) { + ByteVector.fromArray(bspec, byte_in1, i) + .lanewise(VectorOperators.UMAX, + ByteVector.fromArray(bspec, byte_in2, i)) + .intoArray(byte_out, i); + } + } + + @Check(test = "umax_byte", when = CheckAt.COMPILED) + public void umax_byte_verify() { + for (int i = 0; i < COUNT; i++) { + byte actual = byte_out[i]; + byte expected = VectorMath.maxUnsigned(byte_in1[i], byte_in2[i]); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMAX_VS, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umax_short() { + for (int i = 0; i < COUNT; i += sspec.length()) { + ShortVector.fromArray(sspec, short_in1, i) + .lanewise(VectorOperators.UMAX, + ShortVector.fromArray(sspec, short_in2, i)) + .intoArray(short_out, i); + } + } + + @Check(test = "umax_short", when = CheckAt.COMPILED) + public void umax_short_verify() { + for (int i = 0; i < COUNT; i++) { + short actual = short_out[i]; + short expected = VectorMath.maxUnsigned(short_in1[i], short_in2[i]); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMAX_VI, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umax_int() { + for (int i = 0; i < COUNT; i += ispec.length()) { + IntVector.fromArray(ispec, int_in1, i) + .lanewise(VectorOperators.UMAX, + IntVector.fromArray(ispec, int_in2, i)) + .intoArray(int_out, i); + } + } + + @Check(test = "umax_int", when = CheckAt.COMPILED) + public void umax_int_verify() { + for (int i = 0; i < COUNT; i++) { + int actual = int_out[i]; + int expected = VectorMath.maxUnsigned(int_in1[i], int_in2[i]); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMAX_VL, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umax_long() { + for (int i = 0; i < COUNT; i += lspec.length()) { + LongVector.fromArray(lspec, long_in1, i) + .lanewise(VectorOperators.UMAX, + LongVector.fromArray(lspec, long_in2, i)) + .intoArray(long_out, i); + } + } + + @Check(test = "umax_long", when = CheckAt.COMPILED) + public void umax_long_verify() { + for (int i = 0; i < COUNT; i++) { + long actual = long_out[i]; + long expected = VectorMath.maxUnsigned(long_in1[i], long_in2[i]); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMIN_VB, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umin_byte() { + for (int i = 0; i < COUNT; i += bspec.length()) { + ByteVector.fromArray(bspec, byte_in1, i) + .lanewise(VectorOperators.UMIN, + ByteVector.fromArray(bspec, byte_in2, i)) + .intoArray(byte_out, i); + } + } + + @Check(test = "umin_byte", when = CheckAt.COMPILED) + public void umin_byte_verify() { + for (int i = 0; i < COUNT; i++) { + byte actual = byte_out[i]; + byte expected = VectorMath.minUnsigned(byte_in1[i], byte_in2[i]); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMIN_VS, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umin_short() { + for (int i = 0; i < COUNT; i += sspec.length()) { + ShortVector.fromArray(sspec, short_in1, i) + .lanewise(VectorOperators.UMIN, + ShortVector.fromArray(sspec, short_in2, i)) + .intoArray(short_out, i); + } + } + + @Check(test = "umin_short", when = CheckAt.COMPILED) + public void umin_short_verify() { + for (int i = 0; i < COUNT; i++) { + short actual = short_out[i]; + short expected = VectorMath.minUnsigned(short_in1[i], short_in2[i]); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMIN_VI, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umin_int() { + for (int i = 0; i < COUNT; i += ispec.length()) { + IntVector.fromArray(ispec, int_in1, i) + .lanewise(VectorOperators.UMIN, + IntVector.fromArray(ispec, int_in2, i)) + .intoArray(int_out, i); + } + } + + @Check(test = "umin_int", when = CheckAt.COMPILED) + public void umin_int_verify() { + for (int i = 0; i < COUNT; i++) { + int actual = int_out[i]; + int expected = VectorMath.minUnsigned(int_in1[i], int_in2[i]); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMIN_VL, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umin_long() { + for (int i = 0; i < COUNT; i += lspec.length()) { + LongVector.fromArray(lspec, long_in1, i) + .lanewise(VectorOperators.UMIN, + LongVector.fromArray(lspec, long_in2, i)) + .intoArray(long_out, i); + } + } + + @Check(test = "umin_long") + public void umin_long_verify() { + for (int i = 0; i < COUNT; i++) { + long actual = long_out[i]; + long expected = VectorMath.minUnsigned(long_in1[i], long_in2[i]); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMIN_VI, " 0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umin_ir_transform1() { + for (int i = 0; i < COUNT; i += ispec.length()) { + IntVector.fromArray(ispec, int_in1, i) + .lanewise(VectorOperators.UMIN, + IntVector.fromArray(ispec, int_in1, i)) + .intoArray(int_out, i); + } + } + + @Check(test = "umin_ir_transform1", when = CheckAt.COMPILED) + public void umin_ir_transform1_verify() { + for (int i = 0; i < COUNT; i++) { + int actual = int_out[i]; + int expected = VectorMath.minUnsigned(int_in1[i], int_in1[i]); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMAX_VI, " 0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umax_ir_transform1() { + for (int i = 0; i < COUNT; i += ispec.length()) { + IntVector.fromArray(ispec, int_in1, i) + .lanewise(VectorOperators.UMAX, + IntVector.fromArray(ispec, int_in1, i)) + .intoArray(int_out, i); + } + } + + @Check(test = "umax_ir_transform1", when = CheckAt.COMPILED) + public void umax_ir_transform1_verify() { + for (int i = 0; i < COUNT; i++) { + int actual = int_out[i]; + int expected = VectorMath.maxUnsigned(int_in1[i], int_in1[i]); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMAX_VI, " 0 ", IRNode.UMIN_VI, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umin_max_ir_transform1() { + for (int i = 0; i < COUNT; i += ispec.length()) { + IntVector vec1 = IntVector.fromArray(ispec, int_in1, i); + IntVector vec2 = IntVector.fromArray(ispec, int_in2, i); + // UMinV (UMinV vec1, vec2) (UMaxV vec1, vec2) => UMinV vec1 vec2 + vec1.lanewise(VectorOperators.UMIN, vec2) + .lanewise(VectorOperators.UMIN, + vec1.lanewise(VectorOperators.UMAX, vec2)) + .intoArray(int_out, i); + } + } + + @Check(test = "umin_max_ir_transform1", when = CheckAt.COMPILED) + public void umin_max_ir_transform1_verify() { + for (int i = 0; i < COUNT; i++) { + int actual = int_out[i]; + int expected = VectorMath.minUnsigned(VectorMath.minUnsigned(int_in1[i], int_in2[i]), + VectorMath.maxUnsigned(int_in1[i], int_in2[i])); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMIN_VI, " 0 ", IRNode.UMAX_VI, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umin_max_ir_transform2() { + for (int i = 0; i < COUNT; i += ispec.length()) { + IntVector vec1 = IntVector.fromArray(ispec, int_in1, i); + IntVector vec2 = IntVector.fromArray(ispec, int_in2, i); + // UMaxV (UMinV vec2, vec1) (UMaxV vec1, vec2) => UMaxV vec1 vec2 + vec2.lanewise(VectorOperators.UMIN, vec1) + .lanewise(VectorOperators.UMAX, + vec1.lanewise(VectorOperators.UMAX, vec2)) + .intoArray(int_out, i); + } + } + + @Check(test = "umin_max_ir_transform2", when = CheckAt.COMPILED) + public void umin_max_ir_transform2_verify() { + for (int i = 0; i < COUNT; i++) { + int actual = int_out[i]; + int expected = VectorMath.maxUnsigned(VectorMath.minUnsigned(int_in2[i], int_in1[i]), + VectorMath.maxUnsigned(int_in1[i], int_in2[i])); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMAX_VI, " 0 ", IRNode.UMIN_VI, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umin_max_ir_transform3() { + for (int i = 0; i < COUNT; i += ispec.length()) { + IntVector vec1 = IntVector.fromArray(ispec, int_in1, i); + IntVector vec2 = IntVector.fromArray(ispec, int_in2, i); + // UMaxV (UMinV vec1, vec2) (UMinV vec1, vec2) => UMinV vec1 vec2 + vec1.lanewise(VectorOperators.UMIN, vec2) + .lanewise(VectorOperators.UMAX, + vec1.lanewise(VectorOperators.UMIN, vec2)) + .intoArray(int_out, i); + } + } + + @Check(test = "umin_max_ir_transform3", when = CheckAt.COMPILED) + public void umin_max_ir_transform3_verify() { + for (int i = 0; i < COUNT; i++) { + int actual = int_out[i]; + int expected = VectorMath.maxUnsigned(VectorMath.minUnsigned(int_in1[i], int_in2[i]), + VectorMath.minUnsigned(int_in1[i], int_in2[i])); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMIN_VI, " 0 ", IRNode.UMAX_VI, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umin_max_ir_transform4() { + for (int i = 0; i < COUNT; i += ispec.length()) { + IntVector vec1 = IntVector.fromArray(ispec, int_in1, i); + IntVector vec2 = IntVector.fromArray(ispec, int_in2, i); + // UMinV (UMaxV vec2, vec1) (UMaxV vec1, vec2) => UMaxV vec1 vec2 + vec2.lanewise(VectorOperators.UMAX, vec1) + .lanewise(VectorOperators.UMIN, + vec1.lanewise(VectorOperators.UMAX, vec2)) + .intoArray(int_out, i); + } + } + + @Check(test = "umin_max_ir_transform4", when = CheckAt.COMPILED) + public void umin_max_ir_transform4_verify() { + for (int i = 0; i < COUNT; i++) { + int actual = int_out[i]; + int expected = VectorMath.minUnsigned(VectorMath.maxUnsigned(int_in2[i], int_in1[i]), + VectorMath.maxUnsigned(int_in1[i], int_in2[i])); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } + + @Test + @IR(counts = {IRNode.UMIN_VI, " 0 ", IRNode.UMAX_VI, " >0 "}, applyIfCPUFeature = {"avx", "true"}) + @Warmup(value = 10000) + public void umin_max_ir_transform5() { + for (int i = 0; i < COUNT; i += ispec.length()) { + IntVector vec1 = IntVector.fromArray(ispec, int_in1, i); + IntVector vec2 = IntVector.fromArray(ispec, int_in2, i); + // UMaxV (UMinV vec1, vec2) (UMaxV vec2, vec1) => UMaxV vec1 vec2 + vec1.lanewise(VectorOperators.UMIN, vec2) + .lanewise(VectorOperators.UMAX, + vec2.lanewise(VectorOperators.UMAX, vec1)) + .intoArray(int_out, i); + } + } + + @Check(test = "umin_max_ir_transform5", when = CheckAt.COMPILED) + public void umin_max_ir_transform5_verify() { + for (int i = 0; i < COUNT; i++) { + int actual = int_out[i]; + int expected = VectorMath.maxUnsigned(VectorMath.minUnsigned(int_in1[i], int_in2[i]), + VectorMath.maxUnsigned(int_in2[i], int_in1[i])); + if (actual != expected) { + throw new AssertionError("Result Mismatch : actual (" + actual + ") != expected (" + expected + ")"); + } + } + } +} + From 21b0f5ea153c633de7f09bdb0399308c890f7e43 Mon Sep 17 00:00:00 2001 From: Bradford Wetmore Date: Sat, 26 Apr 2025 05:46:05 +0000 Subject: [PATCH 042/118] 8355637: SSLSessionImpl's "serialization" list documentation is incorrectly ordered Reviewed-by: ascarpino --- .../classes/sun/security/ssl/SSLSessionImpl.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java index 2e7d99ee293..566415e23c7 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java @@ -27,7 +27,6 @@ import sun.security.provider.X509Factory; import java.io.IOException; -import java.math.BigInteger; import java.net.InetAddress; import java.nio.ByteBuffer; import java.security.Principal; @@ -279,6 +278,8 @@ final class SSLSessionImpl extends ExtendedSSLSession { * < 1 byte > Number of requestedServerNames entries * < 1 byte > ServerName length * < length in bytes > ServerName + * < 4 bytes > maximumPacketSize + * < 4 bytes > negotiatedMaxFragSize * < 4 bytes > creationTime * < 2 byte > status response length * < 2 byte > status response entry length @@ -304,8 +305,6 @@ final class SSLSessionImpl extends ExtendedSSLSession { * < length in bytes> PSK identity * Anonymous * < 1 byte > - * < 4 bytes > maximumPacketSize - * < 4 bytes > negotiatedMaxFragSize */ SSLSessionImpl(HandshakeContext hc, ByteBuffer buf) throws IOException { @@ -1300,12 +1299,12 @@ public String[] getValueNames() { /** * Use large packet sizes now or follow RFC 2246 packet sizes (2^14) * until changed. - * + *

* In the TLS specification (section 6.2.1, RFC2246), it is not * recommended that the plaintext has more than 2^14 bytes. * However, some TLS implementations violate the specification. * This is a workaround for interoperability with these stacks. - * + *

* Application could accept large fragments up to 2^15 bytes by * setting the system property jsse.SSLEngine.acceptLargeFragments * to "true". @@ -1318,7 +1317,7 @@ public String[] getValueNames() { * Expand the buffer size of both SSL/TLS network packet and * application data. */ - protected void expandBufferSizes() { + void expandBufferSizes() { sessionLock.lock(); try { acceptLargeFragments = true; From 898d4798003d7b9cd54ef3a149eb037998a39887 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sun, 27 Apr 2025 02:29:44 +0000 Subject: [PATCH 043/118] 8355077: Compiler error at splashscreen_gif.c due to unterminated string initialization Reviewed-by: prr --- .../share/native/libsplashscreen/splashscreen_gif.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.desktop/share/native/libsplashscreen/splashscreen_gif.c b/src/java.desktop/share/native/libsplashscreen/splashscreen_gif.c index 3654c677493..cbdad61f78e 100644 --- a/src/java.desktop/share/native/libsplashscreen/splashscreen_gif.c +++ b/src/java.desktop/share/native/libsplashscreen/splashscreen_gif.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ // restore the area overwritten by the graphic with // what was there prior to rendering the graphic. -static const char szNetscape20ext[11] = "NETSCAPE2.0"; +static const char szNetscape20ext[] = "NETSCAPE2.0"; #define NSEXT_LOOP 0x01 // Loop Count field code @@ -181,7 +181,7 @@ SplashDecodeGif(Splash * splash, GifFileType * gif) } case APPLICATION_EXT_FUNC_CODE: { - if (size == sizeof(szNetscape20ext) + if (size == strlen(szNetscape20ext) && memcmp(pExtension, szNetscape20ext, size) == 0) { int iSubCode; From 4e7b5133721f455f84cddecf7dd18ced0d2c8243 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Sun, 27 Apr 2025 06:05:50 +0000 Subject: [PATCH 044/118] 8351333: [ubsan] CDSMapLogger::log_region applying non-zero offset to null pointer Reviewed-by: ccheung --- src/hotspot/share/cds/archiveBuilder.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index c309de17b4c..c1ffd60370b 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -1201,7 +1201,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { #undef _LOG_PREFIX // Log information about a region, whose address at dump time is [base .. top). At - // runtime, this region will be mapped to requested_base. requested_base is 0 if this + // runtime, this region will be mapped to requested_base. requested_base is nullptr if this // region will be mapped at os-selected addresses (such as the bitmap region), or will // be accessed with os::read (the header). // @@ -1210,7 +1210,11 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { static void log_region(const char* name, address base, address top, address requested_base) { size_t size = top - base; base = requested_base; - top = requested_base + size; + if (requested_base == nullptr) { + top = (address)size; + } else { + top = requested_base + size; + } log_info(cds, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " %9zu bytes]", name, p2i(base), p2i(top), size); } From 04bb5dcf5759509e0239a6049db9ae2b97880aa9 Mon Sep 17 00:00:00 2001 From: jeremy Date: Sun, 27 Apr 2025 11:24:29 +0000 Subject: [PATCH 045/118] 8355203: [macos] AquaButtonUI and AquaRootPaneUI repaint default button unnecessarily Reviewed-by: serb, prr --- .../classes/apple/laf/JRSUIConstants.java | 10 +- .../com/apple/laf/AquaButtonBorder.java | 8 +- .../classes/com/apple/laf/AquaButtonUI.java | 34 +-- .../classes/com/apple/laf/AquaRootPaneUI.java | 93 +------ .../RootPane/RootPaneDefaultButtonTest.java | 249 ++++++++++++++++++ 5 files changed, 262 insertions(+), 132 deletions(-) create mode 100644 test/jdk/com/apple/laf/RootPane/RootPaneDefaultButtonTest.java diff --git a/src/java.desktop/macosx/classes/apple/laf/JRSUIConstants.java b/src/java.desktop/macosx/classes/apple/laf/JRSUIConstants.java index 1e98cb19ba4..9da55002b72 100644 --- a/src/java.desktop/macosx/classes/apple/laf/JRSUIConstants.java +++ b/src/java.desktop/macosx/classes/apple/laf/JRSUIConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -194,6 +194,14 @@ public static class State extends Property { @Native private static final byte _pressed = 4; public static final State PRESSED = new State(_pressed); @Native private static final byte _pulsed = 5; + /** + * This identifies the default button in a window/dialog. + * The name PULSED has become misleading over time. + * The default button used to continually pulse up until + * Mac OS 10.9, but now there is no pulsing animation. + * We still need this State constant to render default + * buttons correctly, though. + */ public static final State PULSED = new State(_pulsed); @Native private static final byte _rollover = 6; public static final State ROLLOVER = new State(_rollover); diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonBorder.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonBorder.java index 1d11a0a8d96..60ceb4893a8 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonBorder.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonBorder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -202,12 +202,6 @@ public Dynamic(final Dynamic other) { super(other); } - protected State getButtonState(final AbstractButton b, final ButtonModel model) { - final State state = super.getButtonState(b, model); - painter.state.set(state == State.PULSED ? Animating.YES : Animating.NO); - return state; - } - public Insets getContentInsets(final AbstractButton b, final int width, final int height) { final Size size = AquaUtilControlSize.getUserSizeFrom(b); final Widget style = getStyleForSize(b, size, width, height); diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java index 063923ff807..17818d09121 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,8 +58,6 @@ import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.Border; -import javax.swing.event.AncestorEvent; -import javax.swing.event.AncestorListener; import javax.swing.plaf.ButtonUI; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.RootPaneUI; @@ -225,8 +223,6 @@ protected void installListeners(final AbstractButton b) { // put the listener in the button's client properties so that // we can get at it later b.putClientProperty(this, listener); - - b.addAncestorListener(listener); } installHierListener(b); AquaUtilControlSize.addSizePropertyListener(b); @@ -252,11 +248,7 @@ protected void uninstallKeyboardActions(final AbstractButton b) { protected void uninstallListeners(final AbstractButton b) { super.uninstallListeners(b); - final AquaButtonListener listener = (AquaButtonListener)b.getClientProperty(this); b.putClientProperty(this, null); - if (listener != null) { - b.removeAncestorListener(listener); - } uninstallHierListener(b); AquaUtilControlSize.removeSizePropertyListener(b); } @@ -591,7 +583,7 @@ public void hierarchyChanged(final HierarchyEvent e) { } } - class AquaButtonListener extends BasicButtonListener implements AncestorListener { + class AquaButtonListener extends BasicButtonListener { protected final AbstractButton b; public AquaButtonListener(final AbstractButton b) { @@ -658,27 +650,5 @@ public void propertyChange(final PropertyChangeEvent e) { } } } - - public void ancestorMoved(final AncestorEvent e) {} - - public void ancestorAdded(final AncestorEvent e) { - updateDefaultButton(); - } - - public void ancestorRemoved(final AncestorEvent e) { - updateDefaultButton(); - } - - protected void updateDefaultButton() { - if (!(b instanceof JButton)) return; - if (!((JButton)b).isDefaultButton()) return; - - final JRootPane rootPane = b.getRootPane(); - if (rootPane == null) return; - - final RootPaneUI ui = rootPane.getUI(); - if (!(ui instanceof AquaRootPaneUI)) return; - ((AquaRootPaneUI)ui).updateDefaultButton(rootPane); - } } } diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaRootPaneUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaRootPaneUI.java index 2b4e1bb0867..6bd472b7605 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaRootPaneUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaRootPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,17 +40,10 @@ /** * From AquaRootPaneUI.java * - * The JRootPane manages the default button. There can be only one active rootpane, - * and one default button, so we need only one timer - * * AquaRootPaneUI is a singleton object */ public class AquaRootPaneUI extends BasicRootPaneUI implements AncestorListener, WindowListener, ContainerListener { private static final RecyclableSingleton sRootPaneUI = new RecyclableSingletonFromDefaultConstructor(AquaRootPaneUI.class); - - static final int kDefaultButtonPaintDelayBetweenFrames = 50; - JButton fCurrentDefaultButton = null; - Timer fTimer = null; static final boolean sUseScreenMenuBar = AquaMenuBarUI.getScreenMenuBarProperty(); public static ComponentUI createUI(final JComponent c) { @@ -61,10 +54,6 @@ public void installUI(final JComponent c) { super.installUI(c); c.addAncestorListener(this); - if (c.isShowing() && c.isEnabled()) { - updateDefaultButton((JRootPane)c); - } - // for REGR: Realtime LAF updates no longer work // // because the JFrame parent has a LAF background set (why without a UI element I don't know!) @@ -92,7 +81,6 @@ public void installUI(final JComponent c) { } public void uninstallUI(final JComponent c) { - stopTimer(); c.removeAncestorListener(this); if (sUseScreenMenuBar) { @@ -161,73 +149,6 @@ public void componentRemoved(final ContainerEvent e) { } } - /** - * Invoked when a property changes on the root pane. If the event - * indicates the {@code defaultButton} has changed, this will - * update the animation. - * If the enabled state changed, it will start or stop the animation - */ - public void propertyChange(final PropertyChangeEvent e) { - super.propertyChange(e); - - final String prop = e.getPropertyName(); - if ("defaultButton".equals(prop) || "temporaryDefaultButton".equals(prop)) { - // Change the animating button if this root is showing and enabled - // otherwise do nothing - someone else may be active - final JRootPane root = (JRootPane)e.getSource(); - - if (root.isShowing() && root.isEnabled()) { - updateDefaultButton(root); - } - } else if ("enabled".equals(prop) || AquaFocusHandler.FRAME_ACTIVE_PROPERTY.equals(prop)) { - final JRootPane root = (JRootPane)e.getSource(); - if (root.isShowing()) { - if (((Boolean)e.getNewValue()).booleanValue()) { - updateDefaultButton((JRootPane)e.getSource()); - } else { - stopTimer(); - } - } - } - } - - synchronized void stopTimer() { - if (fTimer != null) { - fTimer.stop(); - fTimer = null; - } - } - - synchronized void updateDefaultButton(final JRootPane root) { - final JButton button = root.getDefaultButton(); - //System.err.println("in updateDefaultButton button = " + button); - fCurrentDefaultButton = button; - stopTimer(); - if (button != null) { - fTimer = new Timer(kDefaultButtonPaintDelayBetweenFrames, new DefaultButtonPainter(root)); - fTimer.start(); - } - } - - class DefaultButtonPainter implements ActionListener { - JRootPane root; - - public DefaultButtonPainter(final JRootPane root) { - this.root = root; - } - - public void actionPerformed(final ActionEvent e) { - final JButton defaultButton = root.getDefaultButton(); - if ((defaultButton != null) && defaultButton.isShowing()) { - if (defaultButton.isEnabled()) { - defaultButton.repaint(); - } - } else { - stopTimer(); - } - } - } - /** * This is sort of like viewDidMoveToWindow:. When the root pane is put into a window * this method gets called for the notification. @@ -249,18 +170,6 @@ public void ancestorAdded(final AncestorEvent event) { owningWindow.removeWindowListener(this); owningWindow.addWindowListener(this); } - - // The root pane has been added to the hierarchy. If it's enabled update the default - // button to start the throbbing. Since the UI is a singleton make sure the root pane - // we are checking has a default button before calling update otherwise we will stop - // throbbing the current default button. - final JComponent comp = event.getComponent(); - if (comp instanceof JRootPane) { - final JRootPane rp = (JRootPane)comp; - if (rp.isEnabled() && rp.getDefaultButton() != null) { - updateDefaultButton((JRootPane)comp); - } - } } /** diff --git a/test/jdk/com/apple/laf/RootPane/RootPaneDefaultButtonTest.java b/test/jdk/com/apple/laf/RootPane/RootPaneDefaultButtonTest.java new file mode 100644 index 00000000000..f314d48841c --- /dev/null +++ b/test/jdk/com/apple/laf/RootPane/RootPaneDefaultButtonTest.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @key headful + * @bug 8344697 + * @summary Default button in AquaRootPaneUI should paint special background color + * @requires (os.family == "mac") + * @run main RootPaneDefaultButtonTest + */ + +import javax.swing.*; +import javax.swing.border.*; +import java.awt.*; +import java.awt.event.*; + +/** + * This presents two dialogs, each with two possible default buttons. The + * background color of the default button should change based on which radio + * button is selected. + *

+ * Note we've never expected this test to fail. This test was introduced + * because the resolution to JDK-8344697 involved removing code, and we wanted + * to double-check that the removed code didn't negatively affect how default + * buttons are repainted. + */ +public class RootPaneDefaultButtonTest extends JDialog { + + record ButtonRenderingExpectation(JButton button, + boolean appearAsDefault) {} + + public static void main(String[] args) throws Exception { + if (!System.getProperty("os.name").contains("OS X")) { + System.out.println("This test is for MacOS only."); + return; + } + + RootPaneDefaultButtonTest window1 = new RootPaneDefaultButtonTest(); + RootPaneDefaultButtonTest window2 = new RootPaneDefaultButtonTest(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + Rectangle r1 = new Rectangle(0, 20, + window1.getWidth(), window1.getHeight()); + window1.setBounds(r1); + + Rectangle r2 = new Rectangle((int) (r1.getMaxX() + 10), 20, + window2.getWidth(), window2.getHeight()); + window2.setBounds(r2); + + window1.setVisible(true); + window2.setVisible(true); + } + }); + + Robot robot = new Robot(); + + test(robot, window1.radioButton1, + new ButtonRenderingExpectation(window1.button1, true), + new ButtonRenderingExpectation(window1.button2, false), + new ButtonRenderingExpectation(window2.button1, false), + new ButtonRenderingExpectation(window2.button2, false)); + + test(robot, window1.radioButton2, + new ButtonRenderingExpectation(window1.button1, false), + new ButtonRenderingExpectation(window1.button2, true), + new ButtonRenderingExpectation(window2.button1, false), + new ButtonRenderingExpectation(window2.button2, false)); + + test(robot, window1.radioButton3, + new ButtonRenderingExpectation(window1.button1, false), + new ButtonRenderingExpectation(window1.button2, false), + new ButtonRenderingExpectation(window2.button1, false), + new ButtonRenderingExpectation(window2.button2, false)); + + test(robot, window2.radioButton1, + new ButtonRenderingExpectation(window1.button1, false), + new ButtonRenderingExpectation(window1.button2, false), + new ButtonRenderingExpectation(window2.button1, true), + new ButtonRenderingExpectation(window2.button2, false)); + + test(robot, window2.radioButton2, + new ButtonRenderingExpectation(window1.button1, false), + new ButtonRenderingExpectation(window1.button2, false), + new ButtonRenderingExpectation(window2.button1, false), + new ButtonRenderingExpectation(window2.button2, true)); + + test(robot, window2.radioButton3, + new ButtonRenderingExpectation(window1.button1, false), + new ButtonRenderingExpectation(window1.button2, false), + new ButtonRenderingExpectation(window2.button1, false), + new ButtonRenderingExpectation(window2.button2, false)); + + System.out.println("Test passed successfully"); + } + + private static void test(Robot robot, AbstractButton buttonToClick, + ButtonRenderingExpectation... expectations) + throws Exception { + robot.delay(100); + + Point mouseLoc = buttonToClick.getLocationOnScreen(); + robot.mouseMove(mouseLoc.x + buttonToClick.getSize().width / 2, + mouseLoc.y + buttonToClick.getSize().height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(20); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.delay(100); + + // the colors may change depending on your system's appearance. + // Depending on how you've configured "Appearance" in the + // System Settings app: the default button may be blue (the default), + // red, purple, etc. So instead of checking for a specific color: we'll + // make sure 3-4 are the same color, and one is significantly + // different. + Color defaultColor = null; + Color nonDefaultColor = null; + + for (ButtonRenderingExpectation expectation : expectations) { + int x = expectation.button.getLocationOnScreen().x + 20; + int y = expectation.button.getLocationOnScreen().y + 10; + + // this mouseMove is optional, but it helps debug this test to see + // where we're sampling the pixel color from: + robot.mouseMove(x, y); + + Color c = robot.getPixelColor(x, y); + if (expectation.appearAsDefault) { + if (defaultColor == null) { + defaultColor = c; + } else { + throw new IllegalStateException( + "there should only be at most 1 default button"); + } + } else { + if (nonDefaultColor == null) { + nonDefaultColor = c; + } else if (!isSimilar(nonDefaultColor, c)) { + throw new IllegalStateException( + "these two colors should match: " + c + ", " + + nonDefaultColor); + } + } + } + + if (defaultColor != null && isSimilar(defaultColor, nonDefaultColor)) { + throw new IllegalStateException( + "The default button and non-default buttons should " + + "look different: " + defaultColor + " matches " + + nonDefaultColor); + } + } + + private static boolean isSimilar(Color c1, Color c2) { + if (Math.abs(c1.getRed() - c2.getRed()) > 15) { + return false; + } + if (Math.abs(c1.getGreen() - c2.getGreen()) > 15) { + return false; + } + if (Math.abs(c1.getBlue() - c2.getBlue()) > 15) { + return false; + } + return true; + } + + JRadioButton radioButton1 = new JRadioButton( + "\"Button 1\" is the default button"); + JRadioButton radioButton2 = new JRadioButton( + "\"Button 2\" is the default button"); + JRadioButton radioButton3 = new JRadioButton("No default button"); + + JButton button1 = new JButton("Button 1"); + JButton button2 = new JButton("Button 2"); + + public RootPaneDefaultButtonTest() { + getContentPane().setLayout(new BorderLayout()); + getContentPane().add(createRadioButtonPanel(), BorderLayout.NORTH); + getContentPane().add(createPushButtonRow(), BorderLayout.SOUTH); + pack(); + + radioButton1.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + getRootPane().setDefaultButton(button1); + } + }); + + radioButton2.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + getRootPane().setDefaultButton(button2); + } + }); + + radioButton3.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + getRootPane().setDefaultButton(null); + } + }); + + ButtonGroup g = new ButtonGroup(); + g.add(radioButton1); + g.add(radioButton2); + g.add(radioButton3); + radioButton1.doClick(); + } + + private JPanel createPushButtonRow() { + JPanel p = new JPanel(new GridLayout(1, 2)); + p.add(button1); + p.add(button2); + p.setBorder(new EmptyBorder(5,5,5,5)); + return p; + } + + private JPanel createRadioButtonPanel() { + JPanel p = new JPanel(new GridLayout(3, 1)); + p.add(radioButton1); + p.add(radioButton2); + p.add(radioButton3); + p.setBorder(new EmptyBorder(5,5,5,5)); + return p; + } +} From 9c86ac27236a67ff7d84447821d89772b993f7e1 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Sun, 27 Apr 2025 11:44:40 +0000 Subject: [PATCH 046/118] 8354495: Open source several AWT DataTransfer tests Reviewed-by: azvegint --- test/jdk/ProblemList.txt | 3 + .../ClipboardPerformanceTest.java | 133 +++++++++++++ .../HTMLTransferConsoleOutputTest.java | 182 ++++++++++++++++++ .../datatransfer/ImageTransferCrashTest.java | 147 ++++++++++++++ 4 files changed, 465 insertions(+) create mode 100644 test/jdk/java/awt/datatransfer/ClipboardPerformanceTest.java create mode 100644 test/jdk/java/awt/datatransfer/HTMLTransferConsoleOutputTest.java create mode 100644 test/jdk/java/awt/datatransfer/ImageTransferCrashTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index b6307d1ed00..c17d8dbe559 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -189,6 +189,9 @@ java/awt/Mouse/EnterExitEvents/DragWindowTest.java 8298823 macosx-all java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowRetaining.java 6829264 generic-all java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java 8080982 generic-all java/awt/datatransfer/SystemFlavorMap/AddFlavorTest.java 8079268 linux-all +java/awt/datatransfer/ClipboardPerformanceTest.java 8029022 windows-all +java/awt/datatransfer/HTMLTransferConsoleOutputTest.java 8237254 macosx-all +java/awt/datatransfer/ImageTransferCrashTest.java 8237253 macosx-all java/awt/Toolkit/RealSync/Test.java 6849383 linux-all java/awt/LightweightComponent/LightweightEventTest/LightweightEventTest.java 8159252 windows-all java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java 8072110 macosx-all diff --git a/test/jdk/java/awt/datatransfer/ClipboardPerformanceTest.java b/test/jdk/java/awt/datatransfer/ClipboardPerformanceTest.java new file mode 100644 index 00000000000..3bad044b949 --- /dev/null +++ b/test/jdk/java/awt/datatransfer/ClipboardPerformanceTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4463560 + * @requires (os.family == "windows") + * @summary Tests that datatransfer doesn't take too much time to complete + * @key headful + * @library /test/lib + * @run main/timeout=300 ClipboardPerformanceTest + */ + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class ClipboardPerformanceTest { + public static final int CODE_FAILURE = 1; + public static final int CODE_OTHER_FAILURE = 2; + static String eoln; + static char[] text; + public static final int ARRAY_SIZE = 100000; + public static final int RATIO_THRESHOLD = 10; + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + ClipboardPerformanceTest clipboardPerformanceTest = new ClipboardPerformanceTest(); + clipboardPerformanceTest.initialize(); + return; + } + + long before, after, oldTime, newTime; + float ratio; + + try { + Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null); + before = System.currentTimeMillis(); + String ss = (String) t.getTransferData(new DataFlavor("text/plain; class=java.lang.String")); + after = System.currentTimeMillis(); + + System.err.println("Size: " + ss.length()); + newTime = after - before; + System.err.println("Time consumed: " + newTime); + + initArray(); + + StringBuffer buf = new StringBuffer(new String(text)); + int eoln_len = eoln.length(); + before = System.currentTimeMillis(); + + for (int i = 0; i + eoln_len <= buf.length(); i++) { + if (eoln.equals(buf.substring(i, i + eoln_len))) { + buf.replace(i, i + eoln_len, "\n"); + } + } + + after = System.currentTimeMillis(); + oldTime = after - before; + System.err.println("Old algorithm: " + oldTime); + ratio = oldTime / newTime; + System.err.println("Ratio: " + ratio); + + if (ratio < RATIO_THRESHOLD) { + System.out.println("Time ratio failure!!"); + System.exit(CODE_FAILURE); + } + } catch (Throwable e) { + e.printStackTrace(); + System.exit(CODE_OTHER_FAILURE); + } + System.out.println("Test Pass!"); + } + + public static void initArray() { + text = new char[ARRAY_SIZE + 2]; + + for (int i = 0; i < ARRAY_SIZE; i += 3) { + text[i] = '\r'; + text[i + 1] = '\n'; + text[i + 2] = 'a'; + } + eoln = "\r\n"; + } + + public void initialize() throws Exception { + initArray(); + Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); + cb.setContents(new StringSelection(new String(text)), null); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + ClipboardPerformanceTest.class.getName(), + "child" + ); + + Process process = ProcessTools.startProcess("Child", pb); + OutputAnalyzer outputAnalyzer = new OutputAnalyzer(process); + + if (!process.waitFor(15, TimeUnit.SECONDS)) { + process.destroyForcibly(); + throw new TimeoutException("Timed out waiting for Child"); + } + + outputAnalyzer.shouldHaveExitValue(0); + } +} diff --git a/test/jdk/java/awt/datatransfer/HTMLTransferConsoleOutputTest.java b/test/jdk/java/awt/datatransfer/HTMLTransferConsoleOutputTest.java new file mode 100644 index 00000000000..6a18a11270f --- /dev/null +++ b/test/jdk/java/awt/datatransfer/HTMLTransferConsoleOutputTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4638351 + * @summary tests that HTML transfer doesn't cause console output + * @key headful + * @library /test/lib + * @run main HTMLTransferConsoleOutputTest + */ + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class HTMLTransferConsoleOutputTest implements ClipboardOwner { + static final Clipboard clipboard = + Toolkit.getDefaultToolkit().getSystemClipboard(); + static final DataFlavor dataFlavor = + new DataFlavor("text/html; class=java.lang.String", null); + static final String magic = "TESTMAGICSTRING"; + static final Transferable transferable = new Transferable() { + final DataFlavor[] flavors = new DataFlavor[]{dataFlavor}; + final String data = "" + magic + ""; + + public DataFlavor[] getTransferDataFlavors() { + return flavors; + } + + public boolean isDataFlavorSupported(DataFlavor df) { + return dataFlavor.equals(df); + } + + public Object getTransferData(DataFlavor df) + throws UnsupportedFlavorException { + if (!isDataFlavorSupported(df)) { + throw new UnsupportedFlavorException(df); + } + return data; + } + }; + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + public static final int CLIPBOARD_DELAY = 1000; + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + HTMLTransferConsoleOutputTest htmlTransferConsoleOutputTest = new HTMLTransferConsoleOutputTest(); + htmlTransferConsoleOutputTest.initialize(); + return; + } + final ClipboardOwner clipboardOwner = new ClipboardOwner() { + public void lostOwnership(Clipboard clip, + Transferable contents) { + System.exit(0); + } + }; + clipboard.setContents(transferable, clipboardOwner); + final Object o = new Object(); + synchronized (o) { + try { + o.wait(); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + } + System.out.println("Test Pass!"); + } + + public void initialize() throws Exception { + clipboard.setContents(transferable, this); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + HTMLTransferConsoleOutputTest.class.getName(), + "child" + ); + + Process process = ProcessTools.startProcess("Child", pb); + OutputAnalyzer outputAnalyzer = new OutputAnalyzer(process); + + if (!process.waitFor(15, TimeUnit.SECONDS)) { + process.destroyForcibly(); + throw new TimeoutException("Timed out waiting for Child"); + } + + byte[] bytes = baos.toByteArray(); + String string = null; + try { + string = new String(bytes, "ASCII"); + } catch (UnsupportedEncodingException uee) { + uee.printStackTrace(); + } + if (string.lastIndexOf(magic) != -1) { + throw new RuntimeException("Test failed. Output contains:" + + string); + } + + outputAnalyzer.shouldHaveExitValue(0); + } + + + static class ForkOutputStream extends OutputStream { + final OutputStream outputStream1; + final OutputStream outputStream2; + + public ForkOutputStream(OutputStream os1, OutputStream os2) { + outputStream1 = os1; + outputStream2 = os2; + } + + public void write(int b) throws IOException { + outputStream1.write(b); + outputStream2.write(b); + } + + public void flush() throws IOException { + outputStream1.flush(); + outputStream2.flush(); + } + + public void close() throws IOException { + outputStream1.close(); + outputStream2.close(); + } + } + + public void lostOwnership(Clipboard clip, Transferable contents) { + final Runnable r = () -> { + try { + Thread.sleep(CLIPBOARD_DELAY); + } catch (InterruptedException e) { + e.printStackTrace(); + } + final PrintStream oldOut = System.out; + final PrintStream newOut = + new PrintStream(new ForkOutputStream(oldOut, baos)); + Transferable t = clipboard.getContents(null); + try { + System.setOut(newOut); + t.getTransferData(dataFlavor); + System.setOut(oldOut); + } catch (IOException | UnsupportedFlavorException ioe) { + ioe.printStackTrace(); + } + clipboard.setContents(transferable, null); + }; + final Thread t = new Thread(r); + t.start(); + } +} diff --git a/test/jdk/java/awt/datatransfer/ImageTransferCrashTest.java b/test/jdk/java/awt/datatransfer/ImageTransferCrashTest.java new file mode 100644 index 00000000000..76e484b3ce2 --- /dev/null +++ b/test/jdk/java/awt/datatransfer/ImageTransferCrashTest.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4513976 + * @summary tests that inter-JVM image transfer doesn't cause crash + * @key headful + * @library /test/lib + * @run main ImageTransferCrashTest + */ + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.image.BufferedImage; +import java.awt.image.WritableRaster; +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class ImageTransferCrashTest implements ClipboardOwner { + static final Clipboard clipboard = + Toolkit.getDefaultToolkit().getSystemClipboard(); + final Transferable textTransferable = new StringSelection("TEXT"); + public static final int CLIPBOARD_DELAY = 10; + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + ImageTransferCrashTest imageTransferCrashTest = new ImageTransferCrashTest(); + imageTransferCrashTest.initialize(); + return; + } + final ClipboardOwner clipboardOwner = (clip, contents) -> System.exit(0); + final int width = 100; + final int height = 100; + final BufferedImage bufferedImage = + new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + final WritableRaster writableRaster = + bufferedImage.getWritableTile(0, 0); + final int[] color = new int[]{0x80, 0x80, 0x80}; + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + writableRaster.setPixel(i, j, color); + } + } + bufferedImage.releaseWritableTile(0, 0); + + final Transferable imageTransferable = new Transferable() { + final DataFlavor[] flavors = new DataFlavor[]{ + DataFlavor.imageFlavor}; + + public DataFlavor[] getTransferDataFlavors() { + return flavors; + } + + public boolean isDataFlavorSupported(DataFlavor df) { + return DataFlavor.imageFlavor.equals(df); + } + + public Object getTransferData(DataFlavor df) + throws UnsupportedFlavorException { + if (!isDataFlavorSupported(df)) { + throw new UnsupportedFlavorException(df); + } + return bufferedImage; + } + }; + clipboard.setContents(imageTransferable, clipboardOwner); + final Object o = new Object(); + synchronized (o) { + try { + o.wait(); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + } + System.out.println("Test Pass!"); + } + + public void initialize() throws Exception { + clipboard.setContents(textTransferable, this); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + ImageTransferCrashTest.class.getName(), + "child" + ); + + Process process = ProcessTools.startProcess("Child", pb); + OutputAnalyzer outputAnalyzer = new OutputAnalyzer(process); + + if (!process.waitFor(15, TimeUnit.SECONDS)) { + process.destroyForcibly(); + throw new TimeoutException("Timed out waiting for Child"); + } + + outputAnalyzer.shouldHaveExitValue(0); + } + + public void lostOwnership(Clipboard clip, Transferable contents) { + final Runnable r = () -> { + while (true) { + try { + Thread.sleep(CLIPBOARD_DELAY); + Transferable t = clipboard.getContents(null); + t.getTransferData(DataFlavor.imageFlavor); + } catch (IllegalStateException e) { + e.printStackTrace(); + System.err.println("clipboard is not prepared yet"); + continue; + } catch (Exception e) { + e.printStackTrace(); + } + break; + } + clipboard.setContents(textTransferable, null); + }; + final Thread t = new Thread(r); + t.start(); + } +} From cd6f0d19d5da03eafde68142528c0f85d783cbea Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Sun, 27 Apr 2025 20:10:20 +0000 Subject: [PATCH 047/118] 8355336: GenShen: Resume Old GC even with back-to-back Young GC triggers Reviewed-by: wkemper --- .../heuristics/shenandoahOldHeuristics.cpp | 9 +++------ .../heuristics/shenandoahYoungHeuristics.cpp | 1 + .../shenandoah/shenandoahRegulatorThread.cpp | 20 ++++++++----------- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp index cf1a76ff4ff..2d0bbfd5e4a 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp @@ -639,12 +639,9 @@ bool ShenandoahOldHeuristics::should_resume_old_cycle() { bool ShenandoahOldHeuristics::should_start_gc() { const ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (_old_generation->is_doing_mixed_evacuations()) { - // Do not try to start an old cycle if we are waiting for old regions to be evacuated (we need - // a young cycle for this). Note that the young heuristic has a feature to expedite old evacuations. - // Future refinement: under certain circumstances, we might be more sophisticated about this choice. - // For example, we could choose to abandon the previous old collection before it has completed evacuations. - log_debug(gc)("Not starting an old cycle because we are waiting for mixed evacuations"); + if (!_old_generation->is_idle()) { + // Do not try to start an old cycle if old-gen is marking, doing mixed evacuations, or coalescing and filling. + log_debug(gc)("Not starting an old cycle because old gen is busy"); return false; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp index ba09eeb8794..3aca436104b 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp @@ -120,6 +120,7 @@ bool ShenandoahYoungHeuristics::should_start_gc() { if (old_time_elapsed < ShenandoahMinimumOldTimeMs) { // Do not decline_trigger() when waiting for minimum quantum of Old-gen marking. It is not at our discretion // to trigger at this time. + log_debug(gc)("Young heuristics declines to trigger because old_time_elapsed < ShenandoahMinimumOldTimeMs"); return false; } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp index bf309af9743..774c4f7d941 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp @@ -67,22 +67,18 @@ void ShenandoahRegulatorThread::regulate_young_and_old_cycles() { _global_heuristics->cancel_trigger_request(); } } else { - if (_young_heuristics->should_start_gc()) { - // Give the old generation a chance to run. The old generation cycle - // begins with a 'bootstrap' cycle that will also collect young. - if (start_old_cycle()) { - log_debug(gc)("Heuristics request for old collection accepted"); - _young_heuristics->cancel_trigger_request(); - _old_heuristics->cancel_trigger_request(); - } else if (request_concurrent_gc(_heap->young_generation())) { - log_debug(gc)("Heuristics request for young collection accepted"); - _young_heuristics->cancel_trigger_request(); - } - } else if (_old_heuristics->should_resume_old_cycle() || _old_heuristics->should_start_gc()) { + if (_old_heuristics->should_resume_old_cycle()) { if (request_concurrent_gc(_heap->old_generation())) { _old_heuristics->cancel_trigger_request(); log_debug(gc)("Heuristics request to resume old collection accepted"); } + } else if (start_old_cycle()) { + log_debug(gc)("Heuristics request for old collection accepted"); + _young_heuristics->cancel_trigger_request(); + _old_heuristics->cancel_trigger_request(); + } else if (start_young_cycle()) { + log_debug(gc)("Heuristics request for young collection accepted"); + _young_heuristics->cancel_trigger_request(); } } } else if (mode == ShenandoahGenerationalControlThread::servicing_old) { From 1f228e5539a5faa3b28e12548f8ad97eeacf3298 Mon Sep 17 00:00:00 2001 From: Damon Fenacci Date: Mon, 28 Apr 2025 06:18:53 +0000 Subject: [PATCH 048/118] 8354119: Missing C2 proper allocation failure handling during initialization (during generate_uncommon_trap_blob) Reviewed-by: kvn, chagedorn, mdoerr, amitkumar, fyang, bulasevich --- src/hotspot/cpu/aarch64/runtime_aarch64.cpp | 6 ++++++ src/hotspot/cpu/arm/runtime_arm.cpp | 6 ++++++ src/hotspot/cpu/ppc/runtime_ppc.cpp | 3 +++ src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 3 +++ src/hotspot/cpu/riscv/runtime_riscv.cpp | 6 ++++++ src/hotspot/cpu/s390/runtime_s390.cpp | 3 +++ src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 3 +++ src/hotspot/cpu/x86/runtime_x86_64.cpp | 6 ++++++ 8 files changed, 36 insertions(+) diff --git a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp index 83e43c3ebd2..2361d584f42 100644 --- a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp @@ -65,6 +65,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); @@ -285,6 +288,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); // TODO check various assumptions made here diff --git a/src/hotspot/cpu/arm/runtime_arm.cpp b/src/hotspot/cpu/arm/runtime_arm.cpp index 20c1bc199d3..615a63eac19 100644 --- a/src/hotspot/cpu/arm/runtime_arm.cpp +++ b/src/hotspot/cpu/arm/runtime_arm.cpp @@ -54,6 +54,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Measured 8/7/03 at 660 in 32bit debug build CodeBuffer buffer(name, 2000, 512); #endif + if (buffer.blob() == nullptr) { + return nullptr; + } // bypassed when code generation useless MacroAssembler* masm = new MacroAssembler(&buffer); const Register Rublock = R6; @@ -209,6 +212,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { // Measured 8/7/03 at 256 in 32bit debug build const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 600, 512); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); int framesize_in_words = 2; // FP + LR diff --git a/src/hotspot/cpu/ppc/runtime_ppc.cpp b/src/hotspot/cpu/ppc/runtime_ppc.cpp index 94e8c08ebf5..6d9a1dfcb1e 100644 --- a/src/hotspot/cpu/ppc/runtime_ppc.cpp +++ b/src/hotspot/cpu/ppc/runtime_ppc.cpp @@ -73,6 +73,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { // Setup code generation tools. const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer); address start = __ pc(); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 5a94d469434..1c9c88b3c30 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -3106,6 +3106,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Setup code generation tools. const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer); address start = __ pc(); diff --git a/src/hotspot/cpu/riscv/runtime_riscv.cpp b/src/hotspot/cpu/riscv/runtime_riscv.cpp index 44a8e35e285..7c8ca853bc4 100644 --- a/src/hotspot/cpu/riscv/runtime_riscv.cpp +++ b/src/hotspot/cpu/riscv/runtime_riscv.cpp @@ -63,6 +63,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); assert_cond(masm != nullptr); @@ -282,6 +285,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); assert_cond(masm != nullptr); diff --git a/src/hotspot/cpu/s390/runtime_s390.cpp b/src/hotspot/cpu/s390/runtime_s390.cpp index 4eedb3877d2..8f96ff55ccb 100644 --- a/src/hotspot/cpu/s390/runtime_s390.cpp +++ b/src/hotspot/cpu/s390/runtime_s390.cpp @@ -72,6 +72,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); Register handle_exception = Z_ARG5; diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index f4487ccabec..099e28a3adc 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -2768,6 +2768,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer); Register unroll_block_reg = Z_tmp_1; diff --git a/src/hotspot/cpu/x86/runtime_x86_64.cpp b/src/hotspot/cpu/x86/runtime_x86_64.cpp index a063c7aeb37..027a523b33d 100644 --- a/src/hotspot/cpu/x86/runtime_x86_64.cpp +++ b/src/hotspot/cpu/x86/runtime_x86_64.cpp @@ -61,6 +61,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); @@ -267,6 +270,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); From 40e7986c412797323f721212d5f375ffe15accb3 Mon Sep 17 00:00:00 2001 From: Nikita Gubarkov Date: Mon, 28 Apr 2025 06:44:16 +0000 Subject: [PATCH 049/118] 8355611: Get rid of SurfaceManagerFactory Reviewed-by: serb, prr --- .../classes/sun/awt/CGraphicsConfig.java | 3 +- .../classes/sun/awt/CGraphicsEnvironment.java | 4 - .../java2d/MacosxSurfaceManagerFactory.java | 57 ------------ .../sun/java2d/metal/MTLGraphicsConfig.java | 10 +- .../sun/java2d/opengl/CGLGraphicsConfig.java | 8 ++ .../sun/awt/image/SunVolatileImage.java | 33 +++---- .../classes/sun/awt/image/SurfaceManager.java | 23 ++++- .../sun/java2d/SurfaceManagerFactory.java | 91 ------------------- .../sun/java2d/opengl/OGLGraphicsConfig.java | 2 +- .../classes/sun/awt/X11GraphicsConfig.java | 10 +- .../classes/sun/awt/X11GraphicsDevice.java | 6 +- .../sun/awt/X11GraphicsEnvironment.java | 6 -- .../sun/java2d/UnixSurfaceManagerFactory.java | 68 -------------- .../sun/java2d/opengl/GLXGraphicsConfig.java | 10 +- .../sun/java2d/xr/XRGraphicsConfig.java | 11 ++- .../classes/sun/awt/Win32GraphicsDevice.java | 3 +- .../sun/awt/Win32GraphicsEnvironment.java | 5 - .../java2d/WindowsSurfaceManagerFactory.java | 66 -------------- .../sun/java2d/d3d/D3DGraphicsConfig.java | 9 +- .../sun/java2d/opengl/WGLGraphicsConfig.java | 10 +- 20 files changed, 103 insertions(+), 332 deletions(-) delete mode 100644 src/java.desktop/macosx/classes/sun/java2d/MacosxSurfaceManagerFactory.java delete mode 100644 src/java.desktop/share/classes/sun/java2d/SurfaceManagerFactory.java delete mode 100644 src/java.desktop/unix/classes/sun/java2d/UnixSurfaceManagerFactory.java delete mode 100644 src/java.desktop/windows/classes/sun/java2d/WindowsSurfaceManagerFactory.java diff --git a/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java b/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java index 3c09758e87f..0ca85104817 100644 --- a/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java +++ b/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java @@ -41,7 +41,8 @@ public abstract class CGraphicsConfig extends GraphicsConfiguration private final CGraphicsDevice device; private ColorModel colorModel; - private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache(); + private final SurfaceManager.ProxyCache surfaceDataProxyCache = + new SurfaceManager.ProxyCache(); protected CGraphicsConfig(CGraphicsDevice device) { this.device = device; diff --git a/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java b/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java index fe4431e3091..e11dabc7a10 100644 --- a/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java +++ b/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java @@ -37,9 +37,7 @@ import java.util.ListIterator; import java.util.Map; -import sun.java2d.MacosxSurfaceManagerFactory; import sun.java2d.SunGraphicsEnvironment; -import sun.java2d.SurfaceManagerFactory; /** * This is an implementation of a GraphicsEnvironment object for the default @@ -70,8 +68,6 @@ public static void init() { } static { // Load libraries and initialize the Toolkit. Toolkit.getDefaultToolkit(); - // Install the correct surface manager factory. - SurfaceManagerFactory.setInstance(new MacosxSurfaceManagerFactory()); } /** diff --git a/src/java.desktop/macosx/classes/sun/java2d/MacosxSurfaceManagerFactory.java b/src/java.desktop/macosx/classes/sun/java2d/MacosxSurfaceManagerFactory.java deleted file mode 100644 index 93fac3fb22a..00000000000 --- a/src/java.desktop/macosx/classes/sun/java2d/MacosxSurfaceManagerFactory.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.java2d; - -import sun.awt.image.SunVolatileImage; -import sun.awt.image.VolatileSurfaceManager; -import sun.awt.CGraphicsDevice; -import sun.java2d.metal.MTLVolatileSurfaceManager; -import sun.java2d.opengl.CGLVolatileSurfaceManager; - -/** - * This is a factory class with static methods for creating a - * platform-specific instance of a particular SurfaceManager. Each platform - * (Windows, Unix, etc.) has its own specialized SurfaceManagerFactory. - */ -public class MacosxSurfaceManagerFactory extends SurfaceManagerFactory { - - /** - * Creates a new instance of a VolatileSurfaceManager given any - * arbitrary SunVolatileImage. An optional context Object can be supplied - * as a way for the caller to pass pipeline-specific context data to - * the VolatileSurfaceManager (such as a backbuffer handle, for example). - * - * For Mac OS X, this method returns either an CGL/MTL-specific - * VolatileSurfaceManager based on the GraphicsConfiguration - * under which the SunVolatileImage was created. - */ - public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg, - Object context) - { - return CGraphicsDevice.usingMetalPipeline() ? new MTLVolatileSurfaceManager(vImg, context) : - new CGLVolatileSurfaceManager(vImg, context); - } -} diff --git a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java index 82adac72c03..e4afec42482 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java +++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java @@ -29,6 +29,8 @@ import sun.awt.CGraphicsDevice; import sun.awt.image.OffScreenImage; import sun.awt.image.SunVolatileImage; +import sun.awt.image.SurfaceManager; +import sun.awt.image.VolatileSurfaceManager; import sun.java2d.Disposer; import sun.java2d.DisposerRecord; import sun.java2d.Surface; @@ -67,7 +69,7 @@ import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_BIOP_SHADER; public final class MTLGraphicsConfig extends CGraphicsConfig - implements AccelGraphicsConfig + implements AccelGraphicsConfig, SurfaceManager.Factory { private static ImageCapabilities imageCaps = new MTLImageCaps(); @@ -372,4 +374,10 @@ public int getMaxTextureHeight() { return Math.max(maxTextureSize / getDevice().getScaleFactor(), getBounds().height); } + + @Override + public VolatileSurfaceManager createVolatileManager(SunVolatileImage image, + Object context) { + return new MTLVolatileSurfaceManager(image, context); + } } diff --git a/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java b/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java index ee9b0aec3a0..6022d516bf9 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java +++ b/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java @@ -46,6 +46,8 @@ import sun.awt.CGraphicsDevice; import sun.awt.image.OffScreenImage; import sun.awt.image.SunVolatileImage; +import sun.awt.image.SurfaceManager; +import sun.awt.image.VolatileSurfaceManager; import sun.java2d.Disposer; import sun.java2d.DisposerRecord; import sun.java2d.Surface; @@ -386,4 +388,10 @@ public int getMaxTextureHeight() { return Math.max(maxTextureSize / getDevice().getScaleFactor(), getBounds().height); } + + @Override + public VolatileSurfaceManager createVolatileManager(SunVolatileImage image, + Object context) { + return new CGLVolatileSurfaceManager(image, context); + } } diff --git a/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java b/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java index 55dfc8db766..4bcd5f6b443 100644 --- a/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java +++ b/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java @@ -37,7 +37,6 @@ import java.awt.image.ImageObserver; import java.awt.image.VolatileImage; import sun.java2d.SunGraphics2D; -import sun.java2d.SurfaceManagerFactory; import sun.java2d.DestSurfaceProvider; import sun.java2d.Surface; import sun.java2d.pipe.Region; @@ -158,29 +157,19 @@ public int getForcedAccelSurfaceType() { return forcedAccelSurfaceType; } - protected VolatileSurfaceManager createSurfaceManager(Object context, - ImageCapabilities caps) - { - /** - * Platform-specific SurfaceManagerFactories will return a - * manager suited to acceleration on each platform. But if - * the user is asking for a VolatileImage from a BufferedImageGC, - * then we need to return the appropriate unaccelerated manager. - * Note: this could change in the future; if some platform would - * like to accelerate BIGC volatile images, then this special-casing - * of the BIGC graphicsConfig should live in platform-specific - * code instead. - * We do the same for a Printer Device, and if user requested an - * unaccelerated VolatileImage by passing the capabilities object. - */ - if (graphicsConfig instanceof BufferedImageGraphicsConfig || - graphicsConfig instanceof sun.print.PrinterGraphicsConfig || - (caps != null && !caps.isAccelerated())) - { + private VolatileSurfaceManager createSurfaceManager( + Object context, ImageCapabilities caps) { + // GraphicsConfig may provide some specific surface manager + // implementation. + // In case it doesn't, or we were specifically requested to use + // an unaccelerated surface, fall back to the buffered image + // surface manager. + if ((caps == null || caps.isAccelerated()) && + graphicsConfig instanceof SurfaceManager.Factory factory) { + return factory.createVolatileManager(this, context); + } else { return new BufImgVolatileSurfaceManager(this, context); } - SurfaceManagerFactory smf = SurfaceManagerFactory.getInstance(); - return smf.createVolatileManager(this, context); } private Color getForeground() { diff --git a/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java b/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java index 9f605eed4e3..9b86d469d98 100644 --- a/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java +++ b/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java @@ -183,6 +183,23 @@ public boolean isAccelerated() { } } + /** + * An interface for GraphicsConfiguration objects to implement if + * they create their own VolatileSurfaceManager implementations. + */ + public interface Factory { + + /** + * Creates a new instance of a VolatileSurfaceManager given a + * compatible SunVolatileImage. + * An optional context Object can be supplied as a way for the caller + * to pass pipeline-specific context data to the VolatileSurfaceManager + * (such as a backbuffer handle, for example). + */ + VolatileSurfaceManager createVolatileManager(SunVolatileImage image, + Object context); + } + /** * An interface for GraphicsConfiguration objects to implement if * their surfaces accelerate images using SurfaceDataProxy objects. @@ -201,7 +218,8 @@ public interface ProxiedGraphicsConfig { } public static class ProxyCache { - private final Map map = Collections.synchronizedMap(new WeakHashMap<>()); + private final Map map = + Collections.synchronizedMap(new WeakHashMap<>()); /** * Return a cached SurfaceDataProxy object for a given SurfaceManager. @@ -252,7 +270,8 @@ public synchronized void flush() { void flush(boolean deaccelerate) { synchronized (weakCache) { - Iterator> i = weakCache.values().iterator(); + Iterator> i = + weakCache.values().iterator(); while (i.hasNext()) { SurfaceDataProxy sdp = i.next().get(); if (sdp == null || sdp.flush(deaccelerate)) { diff --git a/src/java.desktop/share/classes/sun/java2d/SurfaceManagerFactory.java b/src/java.desktop/share/classes/sun/java2d/SurfaceManagerFactory.java deleted file mode 100644 index 39b6d2e33cf..00000000000 --- a/src/java.desktop/share/classes/sun/java2d/SurfaceManagerFactory.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.java2d; - -import sun.awt.image.SunVolatileImage; -import sun.awt.image.VolatileSurfaceManager; - -/** - * This factory creates platform specific VolatileSurfaceManager - * implementations. - * - * There are two platform specific SurfaceManagerFactories in OpenJDK, - * UnixSurfaceManagerFactory and WindowsSurfaceManagerFactory. - * The actually used SurfaceManagerFactory is set by the respective platform - * GraphicsEnvironment implementations in the static initializer. - */ -public abstract class SurfaceManagerFactory { - - /** - * The single shared instance. - */ - private static SurfaceManagerFactory instance; - - /** - * Returns the surface manager factory instance. This returns a factory - * that has been set by {@link #setInstance(SurfaceManagerFactory)}. - * - * @return the surface manager factory - */ - public static synchronized SurfaceManagerFactory getInstance() { - - if (instance == null) { - throw new IllegalStateException("No SurfaceManagerFactory set."); - } - return instance; - } - - /** - * Sets the surface manager factory. This may only be called once, and it - * may not be set back to {@code null} when the factory is already - * instantiated. - * - * @param factory the factory to set - */ - public static synchronized void setInstance(SurfaceManagerFactory factory) { - - if (factory == null) { - // We don't want to allow setting this to null at any time. - throw new IllegalArgumentException("factory must be non-null"); - } - - if (instance != null) { - // We don't want to re-set the instance at any time. - throw new IllegalStateException("The surface manager factory is already initialized"); - } - - instance = factory; - } - - /** - * Creates a new instance of a VolatileSurfaceManager given any - * arbitrary SunVolatileImage. An optional context Object can be supplied - * as a way for the caller to pass pipeline-specific context data to - * the VolatileSurfaceManager (such as a backbuffer handle, for example). - */ - public abstract VolatileSurfaceManager - createVolatileManager(SunVolatileImage image, Object context); -} diff --git a/src/java.desktop/share/classes/sun/java2d/opengl/OGLGraphicsConfig.java b/src/java.desktop/share/classes/sun/java2d/opengl/OGLGraphicsConfig.java index 252644b7e49..a0904588019 100644 --- a/src/java.desktop/share/classes/sun/java2d/opengl/OGLGraphicsConfig.java +++ b/src/java.desktop/share/classes/sun/java2d/opengl/OGLGraphicsConfig.java @@ -35,7 +35,7 @@ * methods directly from OGLSurfaceData. */ interface OGLGraphicsConfig extends - AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig + AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig, SurfaceManager.Factory { OGLContext getContext(); long getNativeConfigInfo(); diff --git a/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java b/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java index ba06574cdd7..9c7a7d5c376 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java +++ b/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java @@ -47,6 +47,7 @@ import sun.awt.image.OffScreenImage; import sun.awt.image.SunVolatileImage; import sun.awt.image.SurfaceManager; +import sun.awt.image.VolatileSurfaceManager; import sun.java2d.Disposer; import sun.java2d.DisposerRecord; import sun.java2d.SurfaceData; @@ -55,6 +56,7 @@ import sun.java2d.loops.SurfaceType; import sun.java2d.pipe.Region; import sun.java2d.x11.X11SurfaceData; +import sun.java2d.x11.X11VolatileSurfaceManager; /** * This is an implementation of a GraphicsConfiguration object for a @@ -64,7 +66,7 @@ * @see GraphicsDevice */ public class X11GraphicsConfig extends GraphicsConfiguration - implements SurfaceManager.ProxiedGraphicsConfig + implements SurfaceManager.ProxiedGraphicsConfig, SurfaceManager.Factory { private final X11GraphicsDevice device; protected int visual; @@ -500,4 +502,10 @@ public boolean isTranslucencyCapable() { } private native boolean isTranslucencyCapable(long x11ConfigData); + + @Override + public VolatileSurfaceManager createVolatileManager(SunVolatileImage image, + Object context) { + return new X11VolatileSurfaceManager(image, context); + } } diff --git a/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java b/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java index 39ecb13c6a4..a7ec9ccc9fd 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java +++ b/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java @@ -62,7 +62,8 @@ public final class X11GraphicsDevice extends GraphicsDevice * therefore methods, which is using this id should be ready to it. */ private volatile int screen; - Map x11ProxyCacheMap = Collections.synchronizedMap(new HashMap<>()); + Map x11ProxyCacheMap = + Collections.synchronizedMap(new HashMap<>()); private static Boolean xrandrExtSupported; private SunDisplayChanger topLevels = new SunDisplayChanger(); @@ -95,7 +96,8 @@ public int getScreen() { } public SurfaceManager.ProxyCache getProxyCacheFor(SurfaceType st) { - return x11ProxyCacheMap.computeIfAbsent(st, unused -> new SurfaceManager.ProxyCache()); + return x11ProxyCacheMap.computeIfAbsent(st, + unused -> new SurfaceManager.ProxyCache()); } /** diff --git a/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java b/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java index 82490e88a99..c24e311017e 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java +++ b/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java @@ -41,8 +41,6 @@ import sun.awt.X11.XToolkit; import sun.java2d.SunGraphicsEnvironment; -import sun.java2d.SurfaceManagerFactory; -import sun.java2d.UnixSurfaceManagerFactory; import sun.java2d.xr.XRSurfaceData; /** @@ -124,10 +122,6 @@ private static void initStatic() { XRSurfaceData.initXRSurfaceData(); } } - - // Install the correct surface manager factory. - SurfaceManagerFactory.setInstance(new UnixSurfaceManagerFactory()); - } diff --git a/src/java.desktop/unix/classes/sun/java2d/UnixSurfaceManagerFactory.java b/src/java.desktop/unix/classes/sun/java2d/UnixSurfaceManagerFactory.java deleted file mode 100644 index 5ab78ee39ee..00000000000 --- a/src/java.desktop/unix/classes/sun/java2d/UnixSurfaceManagerFactory.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package sun.java2d; - -import java.awt.GraphicsConfiguration; - -import sun.awt.image.SunVolatileImage; -import sun.awt.image.VolatileSurfaceManager; -import sun.java2d.opengl.GLXGraphicsConfig; -import sun.java2d.opengl.GLXVolatileSurfaceManager; -import sun.java2d.x11.X11VolatileSurfaceManager; -import sun.java2d.xr.*; - -/** - * The SurfaceManagerFactory that creates VolatileSurfaceManager - * implementations for the Unix volatile images. - */ -public class UnixSurfaceManagerFactory extends SurfaceManagerFactory { - - /** - * Creates a new instance of a VolatileSurfaceManager given any - * arbitrary SunVolatileImage. An optional context Object can be supplied - * as a way for the caller to pass pipeline-specific context data to - * the VolatileSurfaceManager (such as a backbuffer handle, for example). - * - * For Unix platforms, this method returns either an X11- or a GLX- - * specific VolatileSurfaceManager based on the GraphicsConfiguration - * under which the SunVolatileImage was created. - */ - public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg, - Object context) - { - GraphicsConfiguration gc = vImg.getGraphicsConfig(); - - if (gc instanceof GLXGraphicsConfig) { - return new GLXVolatileSurfaceManager(vImg, context); - } else if(gc instanceof XRGraphicsConfig) { - return new XRVolatileSurfaceManager(vImg, context); - }else { - return new X11VolatileSurfaceManager(vImg, context); - } - } - -} diff --git a/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java b/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java index 96b0dc49183..2ea076f8051 100644 --- a/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java +++ b/src/java.desktop/unix/classes/sun/java2d/opengl/GLXGraphicsConfig.java @@ -49,6 +49,7 @@ import sun.awt.image.OffScreenImage; import sun.awt.image.SunVolatileImage; import sun.awt.image.SurfaceManager; +import sun.awt.image.VolatileSurfaceManager; import sun.java2d.SunGraphics2D; import sun.java2d.Surface; import sun.java2d.SurfaceData; @@ -72,7 +73,8 @@ public final class GLXGraphicsConfig private long pConfigInfo; private ContextCapabilities oglCaps; private final OGLContext context; - private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache(); + private final SurfaceManager.ProxyCache surfaceDataProxyCache = + new SurfaceManager.ProxyCache(); private static native long getGLXConfigInfo(int screennum, int visualnum); private static native int getOGLCapabilities(long configInfo); @@ -413,4 +415,10 @@ public ImageCapabilities getImageCapabilities() { public ContextCapabilities getContextCapabilities() { return oglCaps; } + + @Override + public VolatileSurfaceManager createVolatileManager(SunVolatileImage image, + Object context) { + return new GLXVolatileSurfaceManager(image, context); + } } diff --git a/src/java.desktop/unix/classes/sun/java2d/xr/XRGraphicsConfig.java b/src/java.desktop/unix/classes/sun/java2d/xr/XRGraphicsConfig.java index fb2c8ad4801..43f17e11ae1 100644 --- a/src/java.desktop/unix/classes/sun/java2d/xr/XRGraphicsConfig.java +++ b/src/java.desktop/unix/classes/sun/java2d/xr/XRGraphicsConfig.java @@ -30,11 +30,14 @@ import sun.awt.X11GraphicsDevice; import sun.awt.X11GraphicsEnvironment; import sun.awt.image.SurfaceManager; +import sun.awt.image.SunVolatileImage; +import sun.awt.image.VolatileSurfaceManager; import sun.java2d.SurfaceData; public class XRGraphicsConfig extends X11GraphicsConfig implements SurfaceManager.ProxiedGraphicsConfig { - private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache(); + private final SurfaceManager.ProxyCache surfaceDataProxyCache = + new SurfaceManager.ProxyCache(); private XRGraphicsConfig(X11GraphicsDevice device, int visualnum, int depth, int colormap, boolean doubleBuffer) { @@ -59,4 +62,10 @@ public static XRGraphicsConfig getConfig(X11GraphicsDevice device, public SurfaceManager.ProxyCache getSurfaceDataProxyCache() { return surfaceDataProxyCache; } + + @Override + public VolatileSurfaceManager createVolatileManager(SunVolatileImage image, + Object context) { + return new XRVolatileSurfaceManager(image, context); + } } diff --git a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java index 865fe480853..fedc7f38980 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java @@ -89,7 +89,8 @@ public class Win32GraphicsDevice extends GraphicsDevice implements private float scaleX; private float scaleY; - final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache(); + final SurfaceManager.ProxyCache surfaceDataProxyCache = + new SurfaceManager.ProxyCache(); static { diff --git a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java index 09768148f3d..2e11d551059 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java @@ -35,8 +35,6 @@ import sun.awt.windows.WToolkit; import sun.java2d.SunGraphicsEnvironment; -import sun.java2d.SurfaceManagerFactory; -import sun.java2d.WindowsSurfaceManagerFactory; import sun.java2d.d3d.D3DGraphicsDevice; import sun.java2d.windows.WindowsFlags; @@ -63,9 +61,6 @@ public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment { initDisplay(); - // Install correct surface manager factory. - SurfaceManagerFactory.setInstance(new WindowsSurfaceManagerFactory()); - double sx = -1; double sy = -1; if (isUIScaleEnabled()) { diff --git a/src/java.desktop/windows/classes/sun/java2d/WindowsSurfaceManagerFactory.java b/src/java.desktop/windows/classes/sun/java2d/WindowsSurfaceManagerFactory.java deleted file mode 100644 index 4abb8c823f6..00000000000 --- a/src/java.desktop/windows/classes/sun/java2d/WindowsSurfaceManagerFactory.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.java2d; - -import java.awt.GraphicsConfiguration; -import sun.awt.image.BufImgVolatileSurfaceManager; -import sun.awt.image.SunVolatileImage; -import sun.awt.image.VolatileSurfaceManager; -import sun.java2d.d3d.D3DGraphicsConfig; -import sun.java2d.d3d.D3DVolatileSurfaceManager; -import sun.java2d.opengl.WGLGraphicsConfig; -import sun.java2d.opengl.WGLVolatileSurfaceManager; - -/** - * The SurfaceManagerFactory that creates VolatileSurfaceManager - * implementations for the Windows volatile images. - */ -public final class WindowsSurfaceManagerFactory extends SurfaceManagerFactory { - - /** - * Creates a new instance of a VolatileSurfaceManager given any - * arbitrary SunVolatileImage. An optional context Object can be supplied - * as a way for the caller to pass pipeline-specific context data to - * the VolatileSurfaceManager (such as a backbuffer handle, for example). - * - * For Windows platforms, this method returns a Windows-specific - * VolatileSurfaceManager. - */ - @Override - public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg, - Object context) - { - GraphicsConfiguration gc = vImg.getGraphicsConfig(); - if (gc instanceof D3DGraphicsConfig) { - return new D3DVolatileSurfaceManager(vImg, context); - } else if (gc instanceof WGLGraphicsConfig) { - return new WGLVolatileSurfaceManager(vImg, context); - } else { - return new BufImgVolatileSurfaceManager(vImg, context); - } - } - -} diff --git a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsConfig.java b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsConfig.java index aab6b720d6a..8b001317dca 100644 --- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsConfig.java +++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsConfig.java @@ -39,6 +39,7 @@ import sun.awt.Win32GraphicsConfig; import sun.awt.image.SunVolatileImage; import sun.awt.image.SurfaceManager; +import sun.awt.image.VolatileSurfaceManager; import sun.awt.windows.WComponentPeer; import sun.java2d.Surface; import sun.java2d.SurfaceData; @@ -51,7 +52,7 @@ public final class D3DGraphicsConfig extends Win32GraphicsConfig - implements AccelGraphicsConfig + implements AccelGraphicsConfig, SurfaceManager.Factory { private static ImageCapabilities imageCaps = new D3DImageCaps(); @@ -307,4 +308,10 @@ public D3DContext getContext() { public ContextCapabilities getContextCapabilities() { return device.getContextCapabilities(); } + + @Override + public VolatileSurfaceManager createVolatileManager(SunVolatileImage image, + Object context) { + return new D3DVolatileSurfaceManager(image, context); + } } diff --git a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java index c6658bf2914..40d2af5c12a 100644 --- a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java +++ b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLGraphicsConfig.java @@ -43,6 +43,7 @@ import sun.awt.Win32GraphicsDevice; import sun.awt.image.SunVolatileImage; import sun.awt.image.SurfaceManager; +import sun.awt.image.VolatileSurfaceManager; import sun.awt.windows.WComponentPeer; import sun.java2d.Disposer; import sun.java2d.DisposerRecord; @@ -73,7 +74,8 @@ public final class WGLGraphicsConfig private ContextCapabilities oglCaps; private final OGLContext context; private Object disposerReferent = new Object(); - private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache(); + private final SurfaceManager.ProxyCache surfaceDataProxyCache = + new SurfaceManager.ProxyCache(); public static native int getDefaultPixFmt(int screennum); private static native boolean initWGL(); @@ -432,4 +434,10 @@ public ImageCapabilities getImageCapabilities() { public ContextCapabilities getContextCapabilities() { return oglCaps; } + + @Override + public VolatileSurfaceManager createVolatileManager(SunVolatileImage image, + Object context) { + return new WGLVolatileSurfaceManager(image, context); + } } From 7df1bfe27b0486e834f07d9aec43b0dae020731f Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 28 Apr 2025 06:56:09 +0000 Subject: [PATCH 050/118] 8354811: clock_tics_per_sec code duplication between os_linux and os_posix Reviewed-by: lucy, clanger, asteiner --- src/hotspot/os/aix/os_perf_aix.cpp | 5 +---- src/hotspot/os/linux/os_linux.cpp | 8 ++------ src/hotspot/os/posix/os_posix.cpp | 4 ++++ src/hotspot/os/posix/os_posix.hpp | 5 ++++- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hotspot/os/aix/os_perf_aix.cpp b/src/hotspot/os/aix/os_perf_aix.cpp index 0b008a197de..e9feb3fe47d 100644 --- a/src/hotspot/os/aix/os_perf_aix.cpp +++ b/src/hotspot/os/aix/os_perf_aix.cpp @@ -118,7 +118,6 @@ static OSReturn get_lcpu_ticks(perfstat_id_t* lcpu_name, cpu_tick_store_t* ptick * Return CPU load caused by the currently executing process (the jvm). */ static OSReturn get_jvm_load(double* jvm_uload, double* jvm_sload) { - static clock_t ticks_per_sec = sysconf(_SC_CLK_TCK); static u_longlong_t last_timebase = 0; perfstat_process_t jvm_stats; @@ -204,8 +203,6 @@ static bool populate_lcpu_names(int ncpus, perfstat_id_t* lcpu_names) { * (Context Switches / Tick) * (Tick / s) = Context Switches per second */ static OSReturn perf_context_switch_rate(double* rate) { - static clock_t ticks_per_sec = sysconf(_SC_CLK_TCK); - u_longlong_t ticks; perfstat_cpu_total_t cpu_stats; @@ -214,7 +211,7 @@ static OSReturn perf_context_switch_rate(double* rate) { } ticks = cpu_stats.user + cpu_stats.sys + cpu_stats.idle + cpu_stats.wait; - *rate = (cpu_stats.pswitch / ticks) * ticks_per_sec; + *rate = (cpu_stats.pswitch / ticks) * os::Posix::clock_tics_per_second(); return OS_OK; } diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 029d523edc6..22d3e1862b5 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -210,8 +210,6 @@ typedef int (*malloc_info_func_t)(int options, FILE *stream); static malloc_info_func_t g_malloc_info = nullptr; #endif // __GLIBC__ -static int clock_tics_per_sec = 100; - // If the VM might have been created on the primordial thread, we need to resolve the // primordial thread stack bounds and check if the current thread might be the // primordial thread in places. If we know that the primordial thread is never used, @@ -4378,8 +4376,6 @@ static void check_pax(void) { // this is called _before_ most of the global arguments have been parsed void os::init(void) { char dummy; // used to get a guess on initial stack address - - clock_tics_per_sec = checked_cast(sysconf(_SC_CLK_TCK)); int sys_pg_size = checked_cast(sysconf(_SC_PAGESIZE)); if (sys_pg_size < 0) { fatal("os_linux.cpp: os::init: sysconf failed (%s)", @@ -5132,9 +5128,9 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { &user_time, &sys_time); if (count != 13) return -1; if (user_sys_cpu_time) { - return ((jlong)sys_time + (jlong)user_time) * (1000000000 / clock_tics_per_sec); + return ((jlong)sys_time + (jlong)user_time) * (1000000000 / os::Posix::clock_tics_per_second()); } else { - return (jlong)user_time * (1000000000 / clock_tics_per_sec); + return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second()); } } diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index b399ce4bcbf..a331e303913 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1326,6 +1326,10 @@ void os::Posix::init_2(void) { _use_clock_monotonic_condattr ? "CLOCK_MONOTONIC" : "the default clock"); } +int os::Posix::clock_tics_per_second() { + return clock_tics_per_sec; +} + // Utility to convert the given timeout to an absolute timespec // (based on the appropriate clock) to use with pthread_cond_timewait, // and sem_timedwait(). diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp index 248a30d04ad..5c3b1f35bd1 100644 --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,6 +91,9 @@ class os::Posix { static void to_RTC_abstime(timespec* abstime, int64_t millis); + // clock ticks per second of the system + static int clock_tics_per_second(); + static bool handle_stack_overflow(JavaThread* thread, address addr, address pc, const void* ucVoid, address* stub); From a05ff55be4e4e1ab11d756b88a9dfa1f0adb4592 Mon Sep 17 00:00:00 2001 From: Anjian-Wen Date: Mon, 28 Apr 2025 07:15:41 +0000 Subject: [PATCH 051/118] 8355657: RISC-V: Improve PrintOptoAssembly output of vector-scalar instructions Reviewed-by: fyang, gcao --- src/hotspot/cpu/riscv/riscv_v.ad | 162 +++++++++++++++---------------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index d0f31a82069..4e7b36a9fcb 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -415,11 +415,11 @@ instruct vadd_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate add (unpredicated) -instruct vaddI_vi(vReg dst, vReg src1, immI5 con) %{ +instruct vadd_vi(vReg dst, vReg src1, immI5 con) %{ match(Set dst (AddVB src1 (Replicate con))); match(Set dst (AddVS src1 (Replicate con))); match(Set dst (AddVI src1 (Replicate con))); - format %{ "vaddI_vi $dst, $src1, $con" %} + format %{ "vadd_vi $dst, $src1, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -444,11 +444,11 @@ instruct vaddL_vi(vReg dst, vReg src1, immL5 con) %{ // vector-scalar add (unpredicated) -instruct vaddI_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ +instruct vadd_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ match(Set dst (AddVB src1 (Replicate src2))); match(Set dst (AddVS src1 (Replicate src2))); match(Set dst (AddVI src1 (Replicate src2))); - format %{ "vaddI_vx $dst, $src1, $src2" %} + format %{ "vadd_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -473,11 +473,11 @@ instruct vaddL_vx(vReg dst, vReg src1, iRegL src2) %{ // vector-immediate add (predicated) -instruct vaddI_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ +instruct vadd_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ match(Set dst_src (AddVB (Binary dst_src (Replicate con)) v0)); match(Set dst_src (AddVS (Binary dst_src (Replicate con)) v0)); match(Set dst_src (AddVI (Binary dst_src (Replicate con)) v0)); - format %{ "vaddI_vi_masked $dst_src, $dst_src, $con, $v0" %} + format %{ "vadd_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -502,11 +502,11 @@ instruct vaddL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar add (predicated) -instruct vaddI_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ +instruct vadd_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ match(Set dst_src (AddVB (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (AddVS (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (AddVI (Binary dst_src (Replicate src2)) v0)); - format %{ "vaddI_vx_masked $dst_src, $dst_src, $src2, $v0" %} + format %{ "vadd_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -595,11 +595,11 @@ instruct vsub_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-scalar sub (unpredicated) -instruct vsubI_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ +instruct vsub_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ match(Set dst (SubVB src1 (Replicate src2))); match(Set dst (SubVS src1 (Replicate src2))); match(Set dst (SubVI src1 (Replicate src2))); - format %{ "vsubI_vx $dst, $src1, $src2" %} + format %{ "vsub_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -624,11 +624,11 @@ instruct vsubL_vx(vReg dst, vReg src1, iRegL src2) %{ // vector-scalar sub (predicated) -instruct vsubI_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ +instruct vsub_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ match(Set dst_src (SubVB (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (SubVS (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (SubVI (Binary dst_src (Replicate src2)) v0)); - format %{ "vsubI_vx_masked $dst_src, $dst_src, $src2, $v0" %} + format %{ "vsub_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -641,7 +641,7 @@ instruct vsubI_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ instruct vsubL_vx_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ match(Set dst_src (SubVL (Binary dst_src (Replicate src2)) v0)); - format %{ "vsub_vx_masked $dst_src, $dst_src, $src2, $v0" %} + format %{ "vsubL_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vsub_vx(as_VectorRegister($dst_src$$reg), @@ -685,12 +685,12 @@ instruct vand_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate and (unpredicated) -instruct vandI_vi(vReg dst_src, immI5 con) %{ +instruct vand_vi(vReg dst_src, immI5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (AndV dst_src (Replicate con))); - format %{ "vandI_vi $dst_src, $dst_src, $con" %} + format %{ "vand_vi $dst_src, $dst_src, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -716,12 +716,12 @@ instruct vandL_vi(vReg dst_src, immL5 con) %{ // vector-scalar and (unpredicated) -instruct vandI_vx(vReg dst_src, iRegIorL2I src) %{ +instruct vand_vx(vReg dst_src, iRegIorL2I src) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (AndV dst_src (Replicate src))); - format %{ "vandI_vx $dst_src, $dst_src, $src" %} + format %{ "vand_vx $dst_src, $dst_src, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -747,12 +747,12 @@ instruct vandL_vx(vReg dst_src, iRegL src) %{ // vector-immediate and (predicated) -instruct vandI_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ +instruct vand_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (AndV (Binary dst_src (Replicate con)) v0)); - format %{ "vandI_vi_masked $dst_src, $dst_src, $con, $v0" %} + format %{ "vand_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -778,12 +778,12 @@ instruct vandL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar and (predicated) -instruct vandI_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ +instruct vand_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (AndV (Binary dst_src (Replicate src)) v0)); - format %{ "vandI_vx_masked $dst_src, $dst_src, $src, $v0" %} + format %{ "vand_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -841,12 +841,12 @@ instruct vor_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate or (unpredicated) -instruct vorI_vi(vReg dst_src, immI5 con) %{ +instruct vor_vi(vReg dst_src, immI5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (OrV dst_src (Replicate con))); - format %{ "vorI_vi $dst_src, $dst_src, $con" %} + format %{ "vor_vi $dst_src, $dst_src, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -872,12 +872,12 @@ instruct vorL_vi(vReg dst_src, immL5 con) %{ // vector-scalar or (unpredicated) -instruct vorI_vx(vReg dst_src, iRegIorL2I src) %{ +instruct vor_vx(vReg dst_src, iRegIorL2I src) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (OrV dst_src (Replicate src))); - format %{ "vorI_vx $dst_src, $dst_src, $src" %} + format %{ "vor_vx $dst_src, $dst_src, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -903,12 +903,12 @@ instruct vorL_vx(vReg dst_src, iRegL src) %{ // vector-immediate or (predicated) -instruct vorI_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ +instruct vor_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (OrV (Binary dst_src (Replicate con)) v0)); - format %{ "vorI_vi_masked $dst_src, $dst_src, $con, $v0" %} + format %{ "vor_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -934,12 +934,12 @@ instruct vorL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar or (predicated) -instruct vorI_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ +instruct vor_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (OrV (Binary dst_src (Replicate src)) v0)); - format %{ "vorI_vx_masked $dst_src, $dst_src, $src, $v0" %} + format %{ "vor_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -997,12 +997,12 @@ instruct vxor_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate xor (unpredicated) -instruct vxorI_vi(vReg dst_src, immI5 con) %{ +instruct vxor_vi(vReg dst_src, immI5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (XorV dst_src (Replicate con))); - format %{ "vxorI_vi $dst_src, $dst_src, $con" %} + format %{ "vxor_vi $dst_src, $dst_src, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1028,12 +1028,12 @@ instruct vxorL_vi(vReg dst_src, immL5 con) %{ // vector-scalar xor (unpredicated) -instruct vxorI_vx(vReg dst_src, iRegIorL2I src) %{ +instruct vxor_vx(vReg dst_src, iRegIorL2I src) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (XorV dst_src (Replicate src))); - format %{ "vxorI_vx $dst_src, $dst_src, $src" %} + format %{ "vxor_vx $dst_src, $dst_src, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1059,12 +1059,12 @@ instruct vxorL_vx(vReg dst_src, iRegL src) %{ // vector-immediate xor (predicated) -instruct vxorI_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ +instruct vxor_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (XorV (Binary dst_src (Replicate con)) v0)); - format %{ "vxorI_vi_masked $dst_src, $dst_src, $con, $v0" %} + format %{ "vxor_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1090,12 +1090,12 @@ instruct vxorL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar xor (predicated) -instruct vxorI_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ +instruct vxor_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (XorV (Binary dst_src (Replicate src)) v0)); - format %{ "vxorI_vx_masked $dst_src, $dst_src, $src, $v0" %} + format %{ "vxor_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1123,13 +1123,13 @@ instruct vxorL_vx_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ // vector and not -instruct vand_notI(vReg dst, vReg src1, vReg src2, immI_M1 m1) %{ +instruct vand_not(vReg dst, vReg src1, vReg src2, immI_M1 m1) %{ predicate(UseZvbb); predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst (AndV src1 (XorV src2 (Replicate m1)))); - format %{ "vand_notI $dst, $src1, $src2" %} + format %{ "vand_not $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1154,13 +1154,13 @@ instruct vand_notL(vReg dst, vReg src1, vReg src2, immL_M1 m1) %{ ins_pipe(pipe_slow); %} -instruct vand_notI_masked(vReg dst_src1, vReg src2, immI_M1 m1, vRegMask_V0 v0) %{ +instruct vand_not_masked(vReg dst_src1, vReg src2, immI_M1 m1, vRegMask_V0 v0) %{ predicate(UseZvbb); predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (Replicate m1))) v0)); - format %{ "vand_notI_masked $dst_src1, $dst_src1, $src2, $v0" %} + format %{ "vand_not_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1187,13 +1187,13 @@ instruct vand_notL_masked(vReg dst_src1, vReg src2, immL_M1 m1, vRegMask_V0 v0) ins_pipe(pipe_slow); %} -instruct vand_notI_vx(vReg dst, vReg src1, iRegIorL2I src2, immI_M1 m1) %{ +instruct vand_not_vx(vReg dst, vReg src1, iRegIorL2I src2, immI_M1 m1) %{ predicate(UseZvbb); predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst (AndV src1 (Replicate (XorI src2 m1)))); - format %{ "vand_notI_vx $dst, $src1, $src2" %} + format %{ "vand_not_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1218,13 +1218,13 @@ instruct vand_notL_vx(vReg dst, vReg src1, iRegL src2, immL_M1 m1) %{ ins_pipe(pipe_slow); %} -instruct vand_notI_vx_masked(vReg dst_src1, iRegIorL2I src2, immI_M1 m1, vRegMask_V0 v0) %{ +instruct vand_not_vx_masked(vReg dst_src1, iRegIorL2I src2, immI_M1 m1, vRegMask_V0 v0) %{ predicate(UseZvbb); predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src1 (AndV (Binary dst_src1 (Replicate (XorI src2 m1))) v0)); - format %{ "vand_notI_vx_masked $dst_src1, $dst_src1, $src2, $v0" %} + format %{ "vand_not_vx_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1255,12 +1255,12 @@ instruct vand_notL_vx_masked(vReg dst_src1, iRegL src2, immL_M1 m1, vRegMask_V0 // vector not -instruct vnotI(vReg dst, vReg src, immI_M1 m1) %{ +instruct vnot(vReg dst, vReg src, immI_M1 m1) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst (XorV src (Replicate m1))); - format %{ "vnotI $dst, $src" %} + format %{ "vnot $dst, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1286,12 +1286,12 @@ instruct vnotL(vReg dst, vReg src, immL_M1 m1) %{ // vector not - predicated -instruct vnotI_masked(vReg dst_src, immI_M1 m1, vRegMask_V0 v0) %{ +instruct vnot_masked(vReg dst_src, immI_M1 m1, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_INT || Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT); match(Set dst_src (XorV (Binary dst_src (Replicate m1)) v0)); - format %{ "vnotI_masked $dst_src, $dst_src, $v0" %} + format %{ "vnot_masked $dst_src, $dst_src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1801,11 +1801,11 @@ instruct vmul_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-scalar mul (unpredicated) -instruct vmulI_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ +instruct vmul_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ match(Set dst (MulVB src1 (Replicate src2))); match(Set dst (MulVS src1 (Replicate src2))); match(Set dst (MulVI src1 (Replicate src2))); - format %{ "vmulI_vx $dst, $src1, $src2" %} + format %{ "vmul_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1830,11 +1830,11 @@ instruct vmulL_vx(vReg dst, vReg src1, iRegL src2) %{ // vector-scalar mul (predicated) -instruct vmulI_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ +instruct vmul_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ match(Set dst_src (MulVB (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (MulVS (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (MulVI (Binary dst_src (Replicate src2)) v0)); - format %{ "vmulI_vx_masked $dst_src, $dst_src, $src2, $v0" %} + format %{ "vmul_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1921,14 +1921,14 @@ instruct vfneg_masked(vReg dst_src, vRegMask_V0 v0) %{ // vector and reduction -instruct reduce_andI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct reduce_and(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (AndReductionV src1 src2)); effect(TEMP tmp); ins_cost(VEC_COST); - format %{ "reduce_andI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "reduce_and $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -1955,14 +1955,14 @@ instruct reduce_andL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ // vector and reduction - predicated -instruct reduce_andI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct reduce_and_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (AndReductionV (Binary src1 src2) v0)); effect(TEMP tmp); ins_cost(VEC_COST); - format %{ "reduce_andI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "reduce_and_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -1991,14 +1991,14 @@ instruct reduce_andL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v0 // vector or reduction -instruct reduce_orI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct reduce_or(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (OrReductionV src1 src2)); effect(TEMP tmp); ins_cost(VEC_COST); - format %{ "reduce_orI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "reduce_or $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2025,14 +2025,14 @@ instruct reduce_orL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ // vector or reduction - predicated -instruct reduce_orI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct reduce_or_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (OrReductionV (Binary src1 src2) v0)); effect(TEMP tmp); ins_cost(VEC_COST); - format %{ "reduce_orI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "reduce_or_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2061,14 +2061,14 @@ instruct reduce_orL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v0, // vector xor reduction -instruct reduce_xorI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct reduce_xor(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (XorReductionV src1 src2)); effect(TEMP tmp); ins_cost(VEC_COST); - format %{ "reduce_xorI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "reduce_xor $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2095,14 +2095,14 @@ instruct reduce_xorL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ // vector xor reduction - predicated -instruct reduce_xorI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct reduce_xor_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (XorReductionV (Binary src1 src2) v0)); effect(TEMP tmp); ins_cost(VEC_COST); - format %{ "reduce_xorI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "reduce_xor_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2131,14 +2131,14 @@ instruct reduce_xorL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v0 // vector add reduction -instruct reduce_addI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct reduce_add(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (AddReductionVI src1 src2)); effect(TEMP tmp); ins_cost(VEC_COST); - format %{ "reduce_addI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "reduce_add $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2237,14 +2237,14 @@ instruct reduce_addD_unordered(fRegD dst, fRegD src1, vReg src2, vReg tmp) %{ // vector add reduction - predicated -instruct reduce_addI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct reduce_add_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (AddReductionVI (Binary src1 src2) v0)); effect(TEMP tmp); ins_cost(VEC_COST); - format %{ "reduce_addI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "reduce_add_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2303,14 +2303,14 @@ instruct reduce_addD_masked(fRegD dst, fRegD src1, vReg src2, vRegMask_V0 v0, vR // vector integer max reduction -instruct vreduce_maxI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct vreduce_max(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (MaxReductionV src1 src2)); ins_cost(VEC_COST); effect(TEMP tmp); - format %{ "vreduce_maxI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "vreduce_max $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2337,14 +2337,14 @@ instruct vreduce_maxL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ // vector integer max reduction - predicated -instruct vreduce_maxI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct vreduce_max_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (MaxReductionV (Binary src1 src2) v0)); effect(TEMP tmp); ins_cost(VEC_COST); - format %{ "vreduce_maxI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "vreduce_max_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2373,14 +2373,14 @@ instruct vreduce_maxL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v // vector integer min reduction -instruct vreduce_minI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct vreduce_min(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (MinReductionV src1 src2)); ins_cost(VEC_COST); effect(TEMP tmp); - format %{ "vreduce_minI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "vreduce_min $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2407,14 +2407,14 @@ instruct vreduce_minL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ // vector integer min reduction - predicated -instruct vreduce_minI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct vreduce_min_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (MinReductionV (Binary src1 src2) v0)); effect(TEMP tmp); ins_cost(VEC_COST); - format %{ "vreduce_minI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "vreduce_min_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -5157,14 +5157,14 @@ instruct populateindex(vReg dst, iRegIorL2I src1, iRegIorL2I src2, vReg tmp) %{ // BYTE, SHORT, INT -instruct insertI_index_lt32(vReg dst, vReg src, iRegIorL2I val, immI idx, vRegMask_V0 v0) %{ +instruct insert_index_lt32(vReg dst, vReg src, iRegIorL2I val, immI idx, vRegMask_V0 v0) %{ predicate(n->in(2)->get_int() < 32 && (Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT || Matcher::vector_element_basic_type(n) == T_INT)); match(Set dst (VectorInsert (Binary src val) idx)); effect(TEMP v0); - format %{ "insertI_index_lt32 $dst, $src, $val, $idx" %} + format %{ "insert_index_lt32 $dst, $src, $val, $idx" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -5176,14 +5176,14 @@ instruct insertI_index_lt32(vReg dst, vReg src, iRegIorL2I val, immI idx, vRegMa ins_pipe(pipe_slow); %} -instruct insertI_index(vReg dst, vReg src, iRegIorL2I val, iRegIorL2I idx, vReg tmp, vRegMask_V0 v0) %{ +instruct insert_index(vReg dst, vReg src, iRegIorL2I val, iRegIorL2I idx, vReg tmp, vRegMask_V0 v0) %{ predicate(n->in(2)->get_int() >= 32 && (Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT || Matcher::vector_element_basic_type(n) == T_INT)); match(Set dst (VectorInsert (Binary src val) idx)); effect(TEMP tmp, TEMP v0); - format %{ "insertI_index $dst, $src, $val, $idx\t# KILL $tmp" %} + format %{ "insert_index $dst, $src, $val, $idx\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); From 3140de411bb55604f8a9e2484798098d9d141002 Mon Sep 17 00:00:00 2001 From: Bhavana Kilambi Date: Mon, 28 Apr 2025 08:08:42 +0000 Subject: [PATCH 052/118] 8345125: Aarch64: Add aarch64 backend for Float16 scalar operations Reviewed-by: aph, haosun --- src/hotspot/cpu/aarch64/aarch64.ad | 194 ++- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 80 +- src/hotspot/cpu/aarch64/matcher_aarch64.hpp | 6 +- .../cpu/aarch64/vm_version_aarch64.hpp | 4 +- .../vm_version_linux_aarch64.cpp | 14 +- .../classes/jdk/vm/ci/aarch64/AArch64.java | 4 +- test/hotspot/gtest/aarch64/aarch64-asmtest.py | 22 +- test/hotspot/gtest/aarch64/asmtest.out.h | 1452 +++++++++-------- .../c2/irTests/ConvF2HFIdealizationTests.java | 3 + .../irTests/MulHFNodeIdealizationTests.java | 4 + .../irTests/TestFloat16ScalarOperations.java | 66 + .../TestSubNodeFloatDoubleNegation.java | 5 +- .../ir_framework/test/IREncodingPrinter.java | 2 + .../TestFloat16VectorConvChain.java | 2 + 14 files changed, 1102 insertions(+), 756 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index c11c960911f..1b128f2a0ce 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2014, 2024, Red Hat, Inc. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // @@ -2296,6 +2296,26 @@ bool Matcher::match_rule_supported(int opcode) { return false; } break; + case Op_FmaHF: + // UseFMA flag also needs to be checked along with FEAT_FP16 + if (!UseFMA || !is_feat_fp16_supported()) { + return false; + } + break; + case Op_AddHF: + case Op_SubHF: + case Op_MulHF: + case Op_DivHF: + case Op_MinHF: + case Op_MaxHF: + case Op_SqrtHF: + // Half-precision floating point scalar operations require FEAT_FP16 + // to be available. FEAT_FP16 is enabled if both "fphp" and "asimdhp" + // features are supported. + if (!is_feat_fp16_supported()) { + return false; + } + break; } return true; // Per default match rules are supported. @@ -4599,6 +4619,15 @@ operand immF0() interface(CONST_INTER); %} +// Half Float (FP16) Immediate +operand immH() +%{ + match(ConH); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // operand immFPacked() %{ @@ -6942,6 +6971,21 @@ instruct loadConD(vRegD dst, immD con) %{ ins_pipe(fp_load_constant_d); %} +// Load Half Float Constant +// The "ldr" instruction loads a 32-bit word from the constant pool into a +// 32-bit register but only the bottom half will be populated and the top +// 16 bits are zero. +instruct loadConH(vRegF dst, immH con) %{ + match(Set dst con); + format %{ + "ldrs $dst, [$constantaddress]\t# load from constant table: half float=$con\n\t" + %} + ins_encode %{ + __ ldrs(as_FloatRegister($dst$$reg), $constantaddress($con)); + %} + ins_pipe(fp_load_constant_s); +%} + // Store Instructions // Store Byte @@ -13634,6 +13678,17 @@ instruct bits_reverse_L(iRegLNoSp dst, iRegL src) // ============================================================================ // Floating Point Arithmetic Instructions +instruct addHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (AddHF src1 src2)); + format %{ "faddh $dst, $src1, $src2" %} + ins_encode %{ + __ faddh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_dop_reg_reg_s); +%} + instruct addF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (AddF src1 src2)); @@ -13664,6 +13719,17 @@ instruct addD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ ins_pipe(fp_dop_reg_reg_d); %} +instruct subHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (SubHF src1 src2)); + format %{ "fsubh $dst, $src1, $src2" %} + ins_encode %{ + __ fsubh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_dop_reg_reg_s); +%} + instruct subF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (SubF src1 src2)); @@ -13694,6 +13760,17 @@ instruct subD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ ins_pipe(fp_dop_reg_reg_d); %} +instruct mulHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (MulHF src1 src2)); + format %{ "fmulh $dst, $src1, $src2" %} + ins_encode %{ + __ fmulh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_dop_reg_reg_s); +%} + instruct mulF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (MulF src1 src2)); @@ -13724,6 +13801,20 @@ instruct mulD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ ins_pipe(fp_dop_reg_reg_d); %} +// src1 * src2 + src3 (half-precision float) +instruct maddHF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{ + match(Set dst (FmaHF src3 (Binary src1 src2))); + format %{ "fmaddh $dst, $src1, $src2, $src3" %} + ins_encode %{ + assert(UseFMA, "Needs FMA instructions support."); + __ fmaddh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister, + $src3$$FloatRegister); + %} + ins_pipe(pipe_class_default); +%} + // src1 * src2 + src3 instruct maddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{ match(Set dst (FmaF src3 (Binary src1 src2))); @@ -13865,6 +13956,29 @@ instruct mnsubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3, immD0 zer ins_pipe(pipe_class_default); %} +// Math.max(HH)H (half-precision float) +instruct maxHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (MaxHF src1 src2)); + format %{ "fmaxh $dst, $src1, $src2" %} + ins_encode %{ + __ fmaxh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_dop_reg_reg_s); +%} + +// Math.min(HH)H (half-precision float) +instruct minHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (MinHF src1 src2)); + format %{ "fminh $dst, $src1, $src2" %} + ins_encode %{ + __ fminh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_dop_reg_reg_s); +%} // Math.max(FF)F instruct maxF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ @@ -13922,6 +14036,16 @@ instruct minD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ ins_pipe(fp_dop_reg_reg_d); %} +instruct divHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (DivHF src1 src2)); + format %{ "fdivh $dst, $src1, $src2" %} + ins_encode %{ + __ fdivh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_div_s); +%} instruct divF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (DivF src1 src2)); @@ -14095,6 +14219,16 @@ instruct sqrtF_reg(vRegF dst, vRegF src) %{ ins_pipe(fp_div_d); %} +instruct sqrtHF_reg(vRegF dst, vRegF src) %{ + match(Set dst (SqrtHF src)); + format %{ "fsqrth $dst, $src" %} + ins_encode %{ + __ fsqrth($dst$$FloatRegister, + $src$$FloatRegister); + %} + ins_pipe(fp_div_s); +%} + // Math.rint, floor, ceil instruct roundD_reg(vRegD dst, vRegD src, immI rmode) %{ match(Set dst (RoundDoubleMode src rmode)); @@ -17144,6 +17278,64 @@ instruct expandBitsL_memcon(iRegINoSp dst, memory8 mem, immL mask, ins_pipe(pipe_slow); %} +//----------------------------- Reinterpret ---------------------------------- +// Reinterpret a half-precision float value in a floating point register to a general purpose register +instruct reinterpretHF2S(iRegINoSp dst, vRegF src) %{ + match(Set dst (ReinterpretHF2S src)); + format %{ "reinterpretHF2S $dst, $src" %} + ins_encode %{ + __ smov($dst$$Register, $src$$FloatRegister, __ H, 0); + %} + ins_pipe(pipe_slow); +%} + +// Reinterpret a half-precision float value in a general purpose register to a floating point register +instruct reinterpretS2HF(vRegF dst, iRegINoSp src) %{ + match(Set dst (ReinterpretS2HF src)); + format %{ "reinterpretS2HF $dst, $src" %} + ins_encode %{ + __ mov($dst$$FloatRegister, __ H, 0, $src$$Register); + %} + ins_pipe(pipe_slow); +%} + +// Without this optimization, ReinterpretS2HF (ConvF2HF src) would result in the following +// instructions (the first two are for ConvF2HF and the last instruction is for ReinterpretS2HF) - +// fcvt $tmp1_fpr, $src_fpr // Convert float to half-precision float +// mov $tmp2_gpr, $tmp1_fpr // Move half-precision float in FPR to a GPR +// mov $dst_fpr, $tmp2_gpr // Move the result from a GPR to an FPR +// The move from FPR to GPR in ConvF2HF and the move from GPR to FPR in ReinterpretS2HF +// can be omitted in this pattern, resulting in - +// fcvt $dst, $src // Convert float to half-precision float +instruct convF2HFAndS2HF(vRegF dst, vRegF src) +%{ + match(Set dst (ReinterpretS2HF (ConvF2HF src))); + format %{ "convF2HFAndS2HF $dst, $src" %} + ins_encode %{ + __ fcvtsh($dst$$FloatRegister, $src$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + +// Without this optimization, ConvHF2F (ReinterpretHF2S src) would result in the following +// instructions (the first one is for ReinterpretHF2S and the last two are for ConvHF2F) - +// mov $tmp1_gpr, $src_fpr // Move the half-precision float from an FPR to a GPR +// mov $tmp2_fpr, $tmp1_gpr // Move the same value from GPR to an FPR +// fcvt $dst_fpr, $tmp2_fpr // Convert the half-precision float to 32-bit float +// The move from FPR to GPR in ReinterpretHF2S and the move from GPR to FPR in ConvHF2F +// can be omitted as the input (src) is already in an FPR required for the fcvths instruction +// resulting in - +// fcvt $dst, $src // Convert half-precision float to a 32-bit float +instruct convHF2SAndHF2F(vRegF dst, vRegF src) +%{ + match(Set dst (ConvHF2F (ReinterpretHF2S src))); + format %{ "convHF2SAndHF2F $dst, $src" %} + ins_encode %{ + __ fcvths($dst$$FloatRegister, $src$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + // ============================================================================ // This name is KNOWN by the ADLC and cannot be changed. // The ADLC forces a 'TypeRawPtr::BOTTOM' output type diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 3db7d308844..5c02e30963e 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -2032,6 +2032,8 @@ void mvnw(Register Rd, Register Rm, INSN(fsqrtd, 0b01, 0b000011); INSN(fcvtd, 0b01, 0b000100); // Double-precision to single-precision + INSN(fsqrth, 0b11, 0b000011); // Half-precision sqrt + private: void _fcvt_narrow_extend(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, bool do_extend) { @@ -2059,37 +2061,68 @@ void mvnw(Register Rd, Register Rm, #undef INSN // Floating-point data-processing (2 source) - void data_processing(unsigned op31, unsigned type, unsigned opcode, + void data_processing(unsigned op31, unsigned type, unsigned opcode, unsigned op21, FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { starti; f(op31, 31, 29); f(0b11110, 28, 24); - f(type, 23, 22), f(1, 21), f(opcode, 15, 10); + f(type, 23, 22), f(op21, 21), f(opcode, 15, 10); rf(Vm, 16), rf(Vn, 5), rf(Vd, 0); } -#define INSN(NAME, op31, type, opcode) \ +#define INSN(NAME, op31, type, opcode, op21) \ void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \ - data_processing(op31, type, opcode, Vd, Vn, Vm); \ - } - - INSN(fabds, 0b011, 0b10, 0b110101); - INSN(fmuls, 0b000, 0b00, 0b000010); - INSN(fdivs, 0b000, 0b00, 0b000110); - INSN(fadds, 0b000, 0b00, 0b001010); - INSN(fsubs, 0b000, 0b00, 0b001110); - INSN(fmaxs, 0b000, 0b00, 0b010010); - INSN(fmins, 0b000, 0b00, 0b010110); - INSN(fnmuls, 0b000, 0b00, 0b100010); - - INSN(fabdd, 0b011, 0b11, 0b110101); - INSN(fmuld, 0b000, 0b01, 0b000010); - INSN(fdivd, 0b000, 0b01, 0b000110); - INSN(faddd, 0b000, 0b01, 0b001010); - INSN(fsubd, 0b000, 0b01, 0b001110); - INSN(fmaxd, 0b000, 0b01, 0b010010); - INSN(fmind, 0b000, 0b01, 0b010110); - INSN(fnmuld, 0b000, 0b01, 0b100010); + data_processing(op31, type, opcode, op21, Vd, Vn, Vm); \ + } + + INSN(fmuls, 0b000, 0b00, 0b000010, 0b1); + INSN(fdivs, 0b000, 0b00, 0b000110, 0b1); + INSN(fadds, 0b000, 0b00, 0b001010, 0b1); + INSN(fsubs, 0b000, 0b00, 0b001110, 0b1); + INSN(fmaxs, 0b000, 0b00, 0b010010, 0b1); + INSN(fmins, 0b000, 0b00, 0b010110, 0b1); + INSN(fnmuls, 0b000, 0b00, 0b100010, 0b1); + + INSN(fmuld, 0b000, 0b01, 0b000010, 0b1); + INSN(fdivd, 0b000, 0b01, 0b000110, 0b1); + INSN(faddd, 0b000, 0b01, 0b001010, 0b1); + INSN(fsubd, 0b000, 0b01, 0b001110, 0b1); + INSN(fmaxd, 0b000, 0b01, 0b010010, 0b1); + INSN(fmind, 0b000, 0b01, 0b010110, 0b1); + INSN(fnmuld, 0b000, 0b01, 0b100010, 0b1); + + // Half-precision floating-point instructions + INSN(fmulh, 0b000, 0b11, 0b000010, 0b1); + INSN(fdivh, 0b000, 0b11, 0b000110, 0b1); + INSN(faddh, 0b000, 0b11, 0b001010, 0b1); + INSN(fsubh, 0b000, 0b11, 0b001110, 0b1); + INSN(fmaxh, 0b000, 0b11, 0b010010, 0b1); + INSN(fminh, 0b000, 0b11, 0b010110, 0b1); + INSN(fnmulh, 0b000, 0b11, 0b100010, 0b1); +#undef INSN + +// Advanced SIMD scalar three same +#define INSN(NAME, U, size, opcode) \ + void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \ + starti; \ + f(0b01, 31, 30), f(U, 29), f(0b11110, 28, 24), f(size, 23, 22), f(1, 21); \ + rf(Vm, 16), f(opcode, 15, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0); \ + } + + INSN(fabds, 0b1, 0b10, 0b11010); // Floating-point Absolute Difference (single-precision) + INSN(fabdd, 0b1, 0b11, 0b11010); // Floating-point Absolute Difference (double-precision) + +#undef INSN + +// Advanced SIMD scalar three same FP16 +#define INSN(NAME, U, a, opcode) \ + void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \ + starti; \ + f(0b01, 31, 30), f(U, 29), f(0b11110, 28, 24), f(a, 23), f(0b10, 22, 21); \ + rf(Vm, 16), f(0b00, 15, 14), f(opcode, 13, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0); \ + } + + INSN(fabdh, 0b1, 0b1, 0b010); // Floating-point Absolute Difference (half-precision float) #undef INSN @@ -2120,6 +2153,7 @@ void mvnw(Register Rd, Register Rm, INSN(fnmaddd, 0b000, 0b01, 1, 0); INSN(fnmsub, 0b000, 0b01, 1, 1); + INSN(fmaddh, 0b000, 0b11, 0, 0); // half-precision fused multiply-add (scalar) #undef INSN // Floating-point conditional select diff --git a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp index a6cd0557758..0fbc2ef141e 100644 --- a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -200,4 +200,8 @@ return false; } + // Is FEAT_FP16 supported for this CPU? + static bool is_feat_fp16_supported() { + return (VM_Version::supports_fphp() && VM_Version::supports_asimdhp()); + } #endif // CPU_AARCH64_MATCHER_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index 04cf9c9c2a0..373f8da5405 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -125,6 +125,8 @@ enum Ampere_CPU_Model { decl(SHA2, sha256, 6) \ decl(CRC32, crc32, 7) \ decl(LSE, lse, 8) \ + decl(FPHP, fphp, 9) \ + decl(ASIMDHP, asimdhp, 10) \ decl(DCPOP, dcpop, 16) \ decl(SHA3, sha3, 17) \ decl(SHA512, sha512, 21) \ diff --git a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp index dabc69403f3..9725c6cd6c0 100644 --- a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp @@ -75,6 +75,14 @@ #define HWCAP_PACA (1 << 30) #endif +#ifndef HWCAP_FPHP +#define HWCAP_FPHP (1<<9) +#endif + +#ifndef HWCAP_ASIMDHP +#define HWCAP_ASIMDHP (1<<10) +#endif + #ifndef HWCAP2_SVE2 #define HWCAP2_SVE2 (1 << 1) #endif @@ -119,6 +127,8 @@ void VM_Version::get_os_cpu_info() { static_assert(CPU_SHA512 == HWCAP_SHA512, "Flag CPU_SHA512 must follow Linux HWCAP"); static_assert(CPU_SVE == HWCAP_SVE, "Flag CPU_SVE must follow Linux HWCAP"); static_assert(CPU_PACA == HWCAP_PACA, "Flag CPU_PACA must follow Linux HWCAP"); + static_assert(CPU_FPHP == HWCAP_FPHP, "Flag CPU_FPHP must follow Linux HWCAP"); + static_assert(CPU_ASIMDHP == HWCAP_ASIMDHP, "Flag CPU_ASIMDHP must follow Linux HWCAP"); _features = auxv & ( HWCAP_FP | HWCAP_ASIMD | @@ -133,7 +143,9 @@ void VM_Version::get_os_cpu_info() { HWCAP_SHA3 | HWCAP_SHA512 | HWCAP_SVE | - HWCAP_PACA); + HWCAP_PACA | + HWCAP_FPHP | + HWCAP_ASIMDHP); if (auxv2 & HWCAP2_SVE2) _features |= CPU_SVE2; if (auxv2 & HWCAP2_SVEBITPERM) _features |= CPU_SVEBITPERM; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java index 2a8959e5d7f..dbd83b314c9 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -183,6 +183,8 @@ public enum CPUFeature implements CPUFeatureName { SVEBITPERM, SVE2, A53MAC, + FPHP, + ASIMDHP, } private final EnumSet features; diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py index 92868e783dc..866fb7f3e58 100644 --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py @@ -14,10 +14,9 @@ immediates16 \ = [0x1, 0x38, 0x7e, 0xff, 0x1fc, 0x1ff, 0x3f0, - 0x7e0, 0xfc0, 0x1f80, 0x3ff0, 0x7e00, 0x7e00, - 0x8000, 0x81ff, 0xc1ff, 0xc003, 0xc7ff, 0xdfff, - 0xe03f, 0xe10f, 0xe1ff, 0xf801, 0xfc00, 0xfc07, - 0xff03, 0xfffe] + 0x7e0, 0xfc0, 0x1f80, 0x3ff0, 0x7e00, 0x8000, + 0x81ff, 0xc1ff, 0xc003, 0xc7ff, 0xdfff, 0xe03f, + 0xe1ff, 0xf801, 0xfc00, 0xfc07, 0xff03, 0xfffe] immediates32 \ = [0x1, 0x3f, 0x1f0, 0x7e0, @@ -1065,7 +1064,7 @@ class FloatInstruction(Instruction): def aname(self): if (self._name in ["fcvtsh", "fcvths"]): return self._name[:len(self._name)-2] - elif (self._name.endswith("s") | self._name.endswith("d")): + elif (self._name.endswith("h") | self._name.endswith("s") | self._name.endswith("d")): return self._name[:len(self._name)-1] else: return self._name @@ -1684,19 +1683,24 @@ def generate(kind, names): ["maddw", "msubw", "madd", "msub", "smaddl", "smsubl", "umaddl", "umsubl"]) generate(ThreeRegFloatOp, - [["fabds", "sss"], ["fmuls", "sss"], ["fdivs", "sss"], ["fadds", "sss"], ["fsubs", "sss"], + [["fabdh", "hhh"], ["fmulh", "hhh"], ["fdivh", "hhh"], ["faddh", "hhh"], ["fsubh", "hhh"], + ["fmaxh", "hhh"], ["fminh", "hhh"], ["fnmulh", "hhh"], + ["fabds", "sss"], ["fmuls", "sss"], ["fdivs", "sss"], ["fadds", "sss"], ["fsubs", "sss"], + ["fmaxs", "sss"], ["fmins", "sss"], ["fnmuls", "sss"], ["fabdd", "ddd"], ["fmuld", "ddd"], ["fdivd", "ddd"], ["faddd", "ddd"], ["fsubd", "ddd"], + ["fmaxd", "ddd"], ["fmind", "ddd"], ["fnmuld", "ddd"] ]) generate(FourRegFloatOp, - [["fmadds", "ssss"], ["fmsubs", "ssss"], ["fnmadds", "ssss"], ["fnmadds", "ssss"], - ["fmaddd", "dddd"], ["fmsubd", "dddd"], ["fnmaddd", "dddd"], ["fnmaddd", "dddd"],]) + [["fmaddh", "hhhh"], ["fmadds", "ssss"], ["fmsubs", "ssss"], ["fnmadds", "ssss"], + ["fnmadds", "ssss"], ["fmaddd", "dddd"], ["fmsubd", "dddd"], ["fnmaddd", "dddd"], + ["fnmaddd", "dddd"],]) generate(TwoRegFloatOp, [["fmovs", "ss"], ["fabss", "ss"], ["fnegs", "ss"], ["fsqrts", "ss"], ["fcvts", "ds"], ["fcvtsh", "hs"], ["fcvths", "sh"], ["fmovd", "dd"], ["fabsd", "dd"], ["fnegd", "dd"], ["fsqrtd", "dd"], - ["fcvtd", "sd"], + ["fcvtd", "sd"], ["fsqrth", "hh"] ]) generate(FloatConvertOp, [["fcvtzsw", "fcvtzs", "ws"], ["fcvtzs", "fcvtzs", "xs"], diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h index 0c2011592b6..c2e8046213b 100644 --- a/test/hotspot/gtest/aarch64/asmtest.out.h +++ b/test/hotspot/gtest/aarch64/asmtest.out.h @@ -484,404 +484,420 @@ __ umsubl(r13, r10, r7, r5); // umsubl x13, w10, w7, x5 // ThreeRegFloatOp - __ fabds(v30, v15, v3); // fabd s30, s15, s3 - __ fmuls(v12, v12, v16); // fmul s12, s12, s16 - __ fdivs(v31, v31, v18); // fdiv s31, s31, s18 - __ fadds(v19, v21, v16); // fadd s19, s21, s16 - __ fsubs(v15, v10, v21); // fsub s15, s10, s21 - __ fabdd(v2, v10, v28); // fabd d2, d10, d28 - __ fmuld(v7, v30, v31); // fmul d7, d30, d31 - __ fdivd(v18, v1, v2); // fdiv d18, d1, d2 - __ faddd(v6, v10, v3); // fadd d6, d10, d3 - __ fsubd(v25, v11, v7); // fsub d25, d11, d7 + __ fabdh(v30, v15, v3); // fabd h30, h15, h3 + __ fmulh(v12, v12, v16); // fmul h12, h12, h16 + __ fdivh(v31, v31, v18); // fdiv h31, h31, h18 + __ faddh(v19, v21, v16); // fadd h19, h21, h16 + __ fsubh(v15, v10, v21); // fsub h15, h10, h21 + __ fmaxh(v2, v10, v28); // fmax h2, h10, h28 + __ fminh(v7, v30, v31); // fmin h7, h30, h31 + __ fnmulh(v18, v1, v2); // fnmul h18, h1, h2 + __ fabds(v6, v10, v3); // fabd s6, s10, s3 + __ fmuls(v25, v11, v7); // fmul s25, s11, s7 + __ fdivs(v1, v12, v0); // fdiv s1, s12, s0 + __ fadds(v3, v19, v29); // fadd s3, s19, s29 + __ fsubs(v6, v23, v6); // fsub s6, s23, s6 + __ fmaxs(v0, v28, v27); // fmax s0, s28, s27 + __ fmins(v2, v5, v7); // fmin s2, s5, s7 + __ fnmuls(v29, v12, v25); // fnmul s29, s12, s25 + __ fabdd(v13, v12, v24); // fabd d13, d12, d24 + __ fmuld(v19, v8, v18); // fmul d19, d8, d18 + __ fdivd(v22, v26, v21); // fdiv d22, d26, d21 + __ faddd(v20, v19, v2); // fadd d20, d19, d2 + __ fsubd(v30, v22, v8); // fsub d30, d22, d8 + __ fmaxd(v22, v19, v21); // fmax d22, d19, d21 + __ fmind(v12, v18, v21); // fmin d12, d18, d21 + __ fnmuld(v6, v16, v3); // fnmul d6, d16, d3 // FourRegFloatOp - __ fmadds(v1, v12, v0, v3); // fmadd s1, s12, s0, s3 - __ fmsubs(v19, v29, v6, v23); // fmsub s19, s29, s6, s23 - __ fnmadds(v6, v0, v28, v27); // fnmadd s6, s0, s28, s27 - __ fnmadds(v2, v5, v7, v29); // fnmadd s2, s5, s7, s29 - __ fmaddd(v12, v25, v13, v12); // fmadd d12, d25, d13, d12 - __ fmsubd(v24, v19, v8, v18); // fmsub d24, d19, d8, d18 - __ fnmaddd(v22, v26, v21, v20); // fnmadd d22, d26, d21, d20 - __ fnmaddd(v19, v2, v30, v22); // fnmadd d19, d2, d30, d22 + __ fmaddh(v3, v29, v3, v28); // fmadd h3, h29, h3, h28 + __ fmadds(v15, v14, v10, v13); // fmadd s15, s14, s10, s13 + __ fmsubs(v12, v18, v10, v26); // fmsub s12, s18, s10, s26 + __ fnmadds(v7, v7, v15, v29); // fnmadd s7, s7, s15, s29 + __ fnmadds(v0, v23, v0, v12); // fnmadd s0, s23, s0, s12 + __ fmaddd(v24, v14, v13, v8); // fmadd d24, d14, d13, d8 + __ fmsubd(v15, v7, v9, v20); // fmsub d15, d7, d9, d20 + __ fnmaddd(v19, v29, v31, v16); // fnmadd d19, d29, d31, d16 + __ fnmaddd(v2, v9, v16, v21); // fnmadd d2, d9, d16, d21 // TwoRegFloatOp - __ fmovs(v8, v22); // fmov s8, s22 - __ fabss(v19, v21); // fabs s19, s21 - __ fnegs(v12, v18); // fneg s12, s18 - __ fsqrts(v21, v6); // fsqrt s21, s6 - __ fcvts(v16, v3); // fcvt d16, s3 - __ fcvtsh(v3, v29); // fcvt h3, s29 - __ fcvths(v3, v28); // fcvt s3, h28 - __ fmovd(v15, v14); // fmov d15, d14 - __ fabsd(v10, v13); // fabs d10, d13 - __ fnegd(v12, v18); // fneg d12, d18 - __ fsqrtd(v10, v26); // fsqrt d10, d26 - __ fcvtd(v7, v7); // fcvt s7, d7 + __ fmovs(v30, v4); // fmov s30, s4 + __ fabss(v1, v27); // fabs s1, s27 + __ fnegs(v25, v24); // fneg s25, s24 + __ fsqrts(v14, v21); // fsqrt s14, s21 + __ fcvts(v13, v6); // fcvt d13, s6 + __ fcvtsh(v12, v25); // fcvt h12, s25 + __ fcvths(v25, v30); // fcvt s25, h30 + __ fmovd(v28, v21); // fmov d28, d21 + __ fabsd(v16, v23); // fabs d16, d23 + __ fnegd(v5, v29); // fneg d5, d29 + __ fsqrtd(v22, v19); // fsqrt d22, d19 + __ fcvtd(v13, v20); // fcvt s13, d20 + __ fsqrth(v19, v28); // fsqrt h19, h28 // FloatConvertOp - __ fcvtzsw(r14, v29); // fcvtzs w14, s29 - __ fcvtzs(r0, v23); // fcvtzs x0, s23 - __ fcvtzdw(r0, v12); // fcvtzs w0, d12 - __ fcvtzd(r23, v14); // fcvtzs x23, d14 - __ scvtfws(v13, r7); // scvtf s13, w7 - __ scvtfs(v15, r7); // scvtf s15, x7 - __ scvtfwd(v9, r20); // scvtf d9, w20 - __ scvtfd(v19, r28); // scvtf d19, x28 - __ fcvtassw(r30, v16); // fcvtas w30, s16 - __ fcvtasd(r2, v9); // fcvtas x2, d9 - __ fcvtmssw(r16, v21); // fcvtms w16, s21 - __ fcvtmsd(r29, v4); // fcvtms x29, d4 - __ fmovs(r1, v27); // fmov w1, s27 - __ fmovd(r24, v24); // fmov x24, d24 - __ fmovs(v14, r21); // fmov s14, w21 - __ fmovd(v13, r5); // fmov d13, x5 + __ fcvtzsw(r17, v6); // fcvtzs w17, s6 + __ fcvtzs(r13, v7); // fcvtzs x13, s7 + __ fcvtzdw(r28, v26); // fcvtzs w28, d26 + __ fcvtzd(r17, v6); // fcvtzs x17, d6 + __ scvtfws(v1, r4); // scvtf s1, w4 + __ scvtfs(v14, r20); // scvtf s14, x20 + __ scvtfwd(v7, r21); // scvtf d7, w21 + __ scvtfd(v27, r23); // scvtf d27, x23 + __ fcvtassw(r13, v20); // fcvtas w13, s20 + __ fcvtasd(r30, v28); // fcvtas x30, d28 + __ fcvtmssw(r10, v21); // fcvtms w10, s21 + __ fcvtmsd(r5, v17); // fcvtms x5, d17 + __ fmovs(r11, v14); // fmov w11, s14 + __ fmovd(r13, v21); // fmov x13, d21 + __ fmovs(v27, r14); // fmov s27, w14 + __ fmovd(v4, r23); // fmov d4, x23 // TwoRegFloatOp - __ fcmps(v12, v25); // fcmp s12, s25 - __ fcmpd(v25, v30); // fcmp d25, d30 - __ fcmps(v28, 0.0); // fcmp s28, #0.0 - __ fcmpd(v21, 0.0); // fcmp d21, #0.0 + __ fcmps(v24, v30); // fcmp s24, s30 + __ fcmpd(v12, v14); // fcmp d12, d14 + __ fcmps(v17, 0.0); // fcmp s17, #0.0 + __ fcmpd(v28, 0.0); // fcmp d28, #0.0 // LoadStorePairOp - __ stpw(r22, r5, Address(r28, -48)); // stp w22, w5, [x28, #-48] - __ ldpw(r19, r27, Address(r19, 16)); // ldp w19, w27, [x19, #16] - __ ldpsw(r28, r26, Address(r7, -32)); // ldpsw x28, x26, [x7, #-32] - __ stp(r6, r1, Address(r4, -48)); // stp x6, x1, [x4, #-48] - __ ldp(r26, r23, Address(r21, -80)); // ldp x26, x23, [x21, #-80] + __ stpw(r0, r6, Address(r26, 16)); // stp w0, w6, [x26, #16] + __ ldpw(r0, r30, Address(r6, -32)); // ldp w0, w30, [x6, #-32] + __ ldpsw(r16, r2, Address(r11, -208)); // ldpsw x16, x2, [x11, #-208] + __ stp(r15, r0, Address(r12, 128)); // stp x15, x0, [x12, #128] + __ ldp(r7, r30, Address(r23, 32)); // ldp x7, x30, [x23, #32] // LoadStorePairOp - __ stpw(r20, r30, Address(__ pre(r9, -96))); // stp w20, w30, [x9, #-96]! - __ ldpw(r13, r20, Address(__ pre(r26, 16))); // ldp w13, w20, [x26, #16]! - __ ldpsw(r29, r11, Address(__ pre(r13, -80))); // ldpsw x29, x11, [x13, #-80]! - __ stp(r27, r21, Address(__ pre(r5, -48))); // stp x27, x21, [x5, #-48]! - __ ldp(r6, r0, Address(__ pre(r30, 80))); // ldp x6, x0, [x30, #80]! + __ stpw(r26, r15, Address(__ pre(r7, -256))); // stp w26, w15, [x7, #-256]! + __ ldpw(r11, r15, Address(__ pre(r10, -32))); // ldp w11, w15, [x10, #-32]! + __ ldpsw(r19, r16, Address(__ pre(r1, 64))); // ldpsw x19, x16, [x1, #64]! + __ stp(r14, r9, Address(__ pre(r0, 128))); // stp x14, x9, [x0, #128]! + __ ldp(r27, r3, Address(__ pre(r12, -96))); // ldp x27, x3, [x12, #-96]! // LoadStorePairOp - __ stpw(r19, r15, Address(__ post(r16, -208))); // stp w19, w15, [x16], #-208 - __ ldpw(r12, r23, Address(__ post(r9, -240))); // ldp w12, w23, [x9], #-240 - __ ldpsw(r0, r26, Address(__ post(r15, 32))); // ldpsw x0, x26, [x15], #32 - __ stp(r8, r17, Address(__ post(r26, -208))); // stp x8, x17, [x26], #-208 - __ ldp(r25, r7, Address(__ post(r2, -176))); // ldp x25, x7, [x2], #-176 + __ stpw(r8, r11, Address(__ post(r12, -256))); // stp w8, w11, [x12], #-256 + __ ldpw(r10, r16, Address(__ post(r4, 64))); // ldp w10, w16, [x4], #64 + __ ldpsw(r10, r30, Address(__ post(r19, -64))); // ldpsw x10, x30, [x19], #-64 + __ stp(r24, r2, Address(__ post(r15, -96))); // stp x24, x2, [x15], #-96 + __ ldp(r24, r10, Address(__ post(r16, 80))); // ldp x24, x10, [x16], #80 // LoadStorePairOp - __ stnpw(r19, r17, Address(r1, -208)); // stnp w19, w17, [x1, #-208] - __ ldnpw(r0, r13, Address(r22, 128)); // ldnp w0, w13, [x22, #128] - __ stnp(r29, r23, Address(r27, 0)); // stnp x29, x23, [x27, #0] - __ ldnp(r11, r10, Address(r8, -224)); // ldnp x11, x10, [x8, #-224] + __ stnpw(r30, r21, Address(r29, 16)); // stnp w30, w21, [x29, #16] + __ ldnpw(r8, r30, Address(r10, -112)); // ldnp w8, w30, [x10, #-112] + __ stnp(r30, r26, Address(r6, -128)); // stnp x30, x26, [x6, #-128] + __ ldnp(r24, r2, Address(r20, 64)); // ldnp x24, x2, [x20, #64] // LdStNEONOp - __ ld1(v0, __ T8B, Address(r11)); // ld1 {v0.8B}, [x11] - __ ld1(v16, v17, __ T16B, Address(__ post(r26, 32))); // ld1 {v16.16B, v17.16B}, [x26], 32 - __ ld1(v22, v23, v24, __ T1D, Address(__ post(r26, r17))); // ld1 {v22.1D, v23.1D, v24.1D}, [x26], x17 - __ ld1(v27, v28, v29, v30, __ T8H, Address(__ post(r29, 64))); // ld1 {v27.8H, v28.8H, v29.8H, v30.8H}, [x29], 64 - __ ld1r(v22, __ T8B, Address(r6)); // ld1r {v22.8B}, [x6] - __ ld1r(v14, __ T4S, Address(__ post(r29, 4))); // ld1r {v14.4S}, [x29], 4 - __ ld1r(v22, __ T1D, Address(__ post(r12, r16))); // ld1r {v22.1D}, [x12], x16 - __ ld2(v1, v2, __ T2D, Address(r0)); // ld2 {v1.2D, v2.2D}, [x0] - __ ld2(v10, v11, __ T4H, Address(__ post(r21, 16))); // ld2 {v10.4H, v11.4H}, [x21], 16 - __ ld2r(v7, v8, __ T16B, Address(r25)); // ld2r {v7.16B, v8.16B}, [x25] - __ ld2r(v9, v10, __ T2S, Address(__ post(r9, 8))); // ld2r {v9.2S, v10.2S}, [x9], 8 - __ ld2r(v9, v10, __ T2D, Address(__ post(r12, r14))); // ld2r {v9.2D, v10.2D}, [x12], x14 - __ ld3(v7, v8, v9, __ T4S, Address(__ post(r4, r17))); // ld3 {v7.4S, v8.4S, v9.4S}, [x4], x17 - __ ld3(v23, v24, v25, __ T2S, Address(r17)); // ld3 {v23.2S, v24.2S, v25.2S}, [x17] - __ ld3r(v4, v5, v6, __ T8H, Address(r22)); // ld3r {v4.8H, v5.8H, v6.8H}, [x22] - __ ld3r(v13, v14, v15, __ T4S, Address(__ post(r2, 12))); // ld3r {v13.4S, v14.4S, v15.4S}, [x2], 12 - __ ld3r(v16, v17, v18, __ T1D, Address(__ post(r10, r12))); // ld3r {v16.1D, v17.1D, v18.1D}, [x10], x12 - __ ld4(v4, v5, v6, v7, __ T8H, Address(__ post(r2, 64))); // ld4 {v4.8H, v5.8H, v6.8H, v7.8H}, [x2], 64 - __ ld4(v6, v7, v8, v9, __ T8B, Address(__ post(r20, r11))); // ld4 {v6.8B, v7.8B, v8.8B, v9.8B}, [x20], x11 - __ ld4r(v12, v13, v14, v15, __ T8B, Address(r12)); // ld4r {v12.8B, v13.8B, v14.8B, v15.8B}, [x12] - __ ld4r(v16, v17, v18, v19, __ T4H, Address(__ post(r17, 8))); // ld4r {v16.4H, v17.4H, v18.4H, v19.4H}, [x17], 8 - __ ld4r(v14, v15, v16, v17, __ T2S, Address(__ post(r25, r16))); // ld4r {v14.2S, v15.2S, v16.2S, v17.2S}, [x25], x16 + __ ld1(v31, __ T8B, Address(r25)); // ld1 {v31.8B}, [x25] + __ ld1(v5, v6, __ T16B, Address(__ post(r15, 32))); // ld1 {v5.16B, v6.16B}, [x15], 32 + __ ld1(v10, v11, v12, __ T1D, Address(__ post(r7, r13))); // ld1 {v10.1D, v11.1D, v12.1D}, [x7], x13 + __ ld1(v13, v14, v15, v16, __ T8H, Address(__ post(r16, 64))); // ld1 {v13.8H, v14.8H, v15.8H, v16.8H}, [x16], 64 + __ ld1r(v7, __ T8B, Address(r17)); // ld1r {v7.8B}, [x17] + __ ld1r(v16, __ T4S, Address(__ post(r25, 4))); // ld1r {v16.4S}, [x25], 4 + __ ld1r(v11, __ T1D, Address(__ post(r3, r7))); // ld1r {v11.1D}, [x3], x7 + __ ld2(v13, v14, __ T2D, Address(r7)); // ld2 {v13.2D, v14.2D}, [x7] + __ ld2(v9, v10, __ T4H, Address(__ post(r27, 16))); // ld2 {v9.4H, v10.4H}, [x27], 16 + __ ld2r(v6, v7, __ T16B, Address(r26)); // ld2r {v6.16B, v7.16B}, [x26] + __ ld2r(v23, v24, __ T2S, Address(__ post(r16, 8))); // ld2r {v23.2S, v24.2S}, [x16], 8 + __ ld2r(v6, v7, __ T2D, Address(__ post(r13, r8))); // ld2r {v6.2D, v7.2D}, [x13], x8 + __ ld3(v20, v21, v22, __ T4S, Address(__ post(r1, r26))); // ld3 {v20.4S, v21.4S, v22.4S}, [x1], x26 + __ ld3(v15, v16, v17, __ T2S, Address(r15)); // ld3 {v15.2S, v16.2S, v17.2S}, [x15] + __ ld3r(v29, v30, v31, __ T8H, Address(r22)); // ld3r {v29.8H, v30.8H, v31.8H}, [x22] + __ ld3r(v6, v7, v8, __ T4S, Address(__ post(r10, 12))); // ld3r {v6.4S, v7.4S, v8.4S}, [x10], 12 + __ ld3r(v15, v16, v17, __ T1D, Address(__ post(r6, r15))); // ld3r {v15.1D, v16.1D, v17.1D}, [x6], x15 + __ ld4(v6, v7, v8, v9, __ T8H, Address(__ post(r10, 64))); // ld4 {v6.8H, v7.8H, v8.8H, v9.8H}, [x10], 64 + __ ld4(v11, v12, v13, v14, __ T8B, Address(__ post(r3, r7))); // ld4 {v11.8B, v12.8B, v13.8B, v14.8B}, [x3], x7 + __ ld4r(v12, v13, v14, v15, __ T8B, Address(r25)); // ld4r {v12.8B, v13.8B, v14.8B, v15.8B}, [x25] + __ ld4r(v11, v12, v13, v14, __ T4H, Address(__ post(r15, 8))); // ld4r {v11.4H, v12.4H, v13.4H, v14.4H}, [x15], 8 + __ ld4r(v30, v31, v0, v1, __ T2S, Address(__ post(r6, r28))); // ld4r {v30.2S, v31.2S, v0.2S, v1.2S}, [x6], x28 // NEONReduceInstruction - __ addv(v20, __ T8B, v21); // addv b20, v21.8B - __ addv(v1, __ T16B, v2); // addv b1, v2.16B - __ addv(v23, __ T4H, v24); // addv h23, v24.4H - __ addv(v30, __ T8H, v31); // addv h30, v31.8H - __ addv(v14, __ T4S, v15); // addv s14, v15.4S - __ smaxv(v2, __ T8B, v3); // smaxv b2, v3.8B - __ smaxv(v6, __ T16B, v7); // smaxv b6, v7.16B - __ smaxv(v3, __ T4H, v4); // smaxv h3, v4.4H - __ smaxv(v8, __ T8H, v9); // smaxv h8, v9.8H - __ smaxv(v25, __ T4S, v26); // smaxv s25, v26.4S - __ fmaxv(v0, __ T4S, v1); // fmaxv s0, v1.4S - __ sminv(v27, __ T8B, v28); // sminv b27, v28.8B - __ uminv(v30, __ T8B, v31); // uminv b30, v31.8B - __ sminv(v5, __ T16B, v6); // sminv b5, v6.16B - __ uminv(v5, __ T16B, v6); // uminv b5, v6.16B - __ sminv(v30, __ T4H, v31); // sminv h30, v31.4H - __ uminv(v11, __ T4H, v12); // uminv h11, v12.4H - __ sminv(v25, __ T8H, v26); // sminv h25, v26.8H - __ uminv(v0, __ T8H, v1); // uminv h0, v1.8H + __ addv(v27, __ T8B, v28); // addv b27, v28.8B + __ addv(v28, __ T16B, v29); // addv b28, v29.16B + __ addv(v1, __ T4H, v2); // addv h1, v2.4H + __ addv(v28, __ T8H, v29); // addv h28, v29.8H + __ addv(v1, __ T4S, v2); // addv s1, v2.4S + __ smaxv(v20, __ T8B, v21); // smaxv b20, v21.8B + __ smaxv(v29, __ T16B, v30); // smaxv b29, v30.16B + __ smaxv(v16, __ T4H, v17); // smaxv h16, v17.4H + __ smaxv(v13, __ T8H, v14); // smaxv h13, v14.8H + __ smaxv(v10, __ T4S, v11); // smaxv s10, v11.4S + __ fmaxv(v29, __ T4S, v30); // fmaxv s29, v30.4S + __ sminv(v29, __ T8B, v30); // sminv b29, v30.8B + __ uminv(v19, __ T8B, v20); // uminv b19, v20.8B + __ sminv(v22, __ T16B, v23); // sminv b22, v23.16B + __ uminv(v10, __ T16B, v11); // uminv b10, v11.16B + __ sminv(v4, __ T4H, v5); // sminv h4, v5.4H + __ uminv(v31, __ T4H, v0); // uminv h31, v0.4H + __ sminv(v21, __ T8H, v22); // sminv h21, v22.8H + __ uminv(v8, __ T8H, v9); // uminv h8, v9.8H __ sminv(v31, __ T4S, v0); // sminv s31, v0.4S - __ uminv(v0, __ T4S, v1); // uminv s0, v1.4S - __ fminv(v19, __ T4S, v20); // fminv s19, v20.4S - __ fmaxp(v29, v30, __ S); // fmaxp s29, v30.2S - __ fmaxp(v26, v27, __ D); // fmaxp d26, v27.2D - __ fminp(v9, v10, __ S); // fminp s9, v10.2S - __ fminp(v26, v27, __ D); // fminp d26, v27.2D + __ uminv(v19, __ T4S, v20); // uminv s19, v20.4S + __ fminv(v10, __ T4S, v11); // fminv s10, v11.4S + __ fmaxp(v28, v29, __ S); // fmaxp s28, v29.2S + __ fmaxp(v2, v3, __ D); // fmaxp d2, v3.2D + __ fminp(v25, v26, __ S); // fminp s25, v26.2S + __ fminp(v5, v6, __ D); // fminp d5, v6.2D // NEONFloatCompareWithZero - __ fcm(Assembler::GT, v12, __ T2S, v13); // fcmgt v12.2S, v13.2S, #0.0 - __ fcm(Assembler::GT, v15, __ T4S, v16); // fcmgt v15.4S, v16.4S, #0.0 - __ fcm(Assembler::GT, v11, __ T2D, v12); // fcmgt v11.2D, v12.2D, #0.0 - __ fcm(Assembler::GE, v11, __ T2S, v12); // fcmge v11.2S, v12.2S, #0.0 - __ fcm(Assembler::GE, v18, __ T4S, v19); // fcmge v18.4S, v19.4S, #0.0 - __ fcm(Assembler::GE, v25, __ T2D, v26); // fcmge v25.2D, v26.2D, #0.0 - __ fcm(Assembler::EQ, v22, __ T2S, v23); // fcmeq v22.2S, v23.2S, #0.0 + __ fcm(Assembler::GT, v3, __ T2S, v4); // fcmgt v3.2S, v4.2S, #0.0 + __ fcm(Assembler::GT, v8, __ T4S, v9); // fcmgt v8.4S, v9.4S, #0.0 + __ fcm(Assembler::GT, v22, __ T2D, v23); // fcmgt v22.2D, v23.2D, #0.0 + __ fcm(Assembler::GE, v19, __ T2S, v20); // fcmge v19.2S, v20.2S, #0.0 + __ fcm(Assembler::GE, v13, __ T4S, v14); // fcmge v13.4S, v14.4S, #0.0 + __ fcm(Assembler::GE, v5, __ T2D, v6); // fcmge v5.2D, v6.2D, #0.0 + __ fcm(Assembler::EQ, v29, __ T2S, v30); // fcmeq v29.2S, v30.2S, #0.0 __ fcm(Assembler::EQ, v24, __ T4S, v25); // fcmeq v24.4S, v25.4S, #0.0 - __ fcm(Assembler::EQ, v0, __ T2D, v1); // fcmeq v0.2D, v1.2D, #0.0 - __ fcm(Assembler::LT, v17, __ T2S, v18); // fcmlt v17.2S, v18.2S, #0.0 - __ fcm(Assembler::LT, v11, __ T4S, v12); // fcmlt v11.4S, v12.4S, #0.0 - __ fcm(Assembler::LT, v6, __ T2D, v7); // fcmlt v6.2D, v7.2D, #0.0 - __ fcm(Assembler::LE, v29, __ T2S, v30); // fcmle v29.2S, v30.2S, #0.0 - __ fcm(Assembler::LE, v6, __ T4S, v7); // fcmle v6.4S, v7.4S, #0.0 - __ fcm(Assembler::LE, v5, __ T2D, v6); // fcmle v5.2D, v6.2D, #0.0 + __ fcm(Assembler::EQ, v21, __ T2D, v22); // fcmeq v21.2D, v22.2D, #0.0 + __ fcm(Assembler::LT, v26, __ T2S, v27); // fcmlt v26.2S, v27.2S, #0.0 + __ fcm(Assembler::LT, v24, __ T4S, v25); // fcmlt v24.4S, v25.4S, #0.0 + __ fcm(Assembler::LT, v3, __ T2D, v4); // fcmlt v3.2D, v4.2D, #0.0 + __ fcm(Assembler::LE, v24, __ T2S, v25); // fcmle v24.2S, v25.2S, #0.0 + __ fcm(Assembler::LE, v26, __ T4S, v27); // fcmle v26.4S, v27.4S, #0.0 + __ fcm(Assembler::LE, v23, __ T2D, v24); // fcmle v23.2D, v24.2D, #0.0 // TwoRegNEONOp - __ absr(v5, __ T8B, v6); // abs v5.8B, v6.8B + __ absr(v15, __ T8B, v16); // abs v15.8B, v16.8B __ absr(v21, __ T16B, v22); // abs v21.16B, v22.16B - __ absr(v19, __ T4H, v20); // abs v19.4H, v20.4H - __ absr(v16, __ T8H, v17); // abs v16.8H, v17.8H - __ absr(v18, __ T2S, v19); // abs v18.2S, v19.2S - __ absr(v30, __ T4S, v31); // abs v30.4S, v31.4S - __ absr(v27, __ T2D, v28); // abs v27.2D, v28.2D - __ fabs(v28, __ T2S, v29); // fabs v28.2S, v29.2S - __ fabs(v1, __ T4S, v2); // fabs v1.4S, v2.4S - __ fabs(v28, __ T2D, v29); // fabs v28.2D, v29.2D + __ absr(v3, __ T4H, v4); // abs v3.4H, v4.4H + __ absr(v24, __ T8H, v25); // abs v24.8H, v25.8H + __ absr(v8, __ T2S, v9); // abs v8.2S, v9.2S + __ absr(v25, __ T4S, v26); // abs v25.4S, v26.4S + __ absr(v20, __ T2D, v21); // abs v20.2D, v21.2D + __ fabs(v16, __ T2S, v17); // fabs v16.2S, v17.2S + __ fabs(v17, __ T4S, v18); // fabs v17.4S, v18.4S + __ fabs(v2, __ T2D, v3); // fabs v2.2D, v3.2D __ fneg(v1, __ T2S, v2); // fneg v1.2S, v2.2S - __ fneg(v20, __ T4S, v21); // fneg v20.4S, v21.4S - __ fneg(v29, __ T2D, v30); // fneg v29.2D, v30.2D - __ fsqrt(v16, __ T2S, v17); // fsqrt v16.2S, v17.2S - __ fsqrt(v13, __ T4S, v14); // fsqrt v13.4S, v14.4S - __ fsqrt(v10, __ T2D, v11); // fsqrt v10.2D, v11.2D - __ notr(v29, __ T8B, v30); // not v29.8B, v30.8B - __ notr(v29, __ T16B, v30); // not v29.16B, v30.16B + __ fneg(v0, __ T4S, v1); // fneg v0.4S, v1.4S + __ fneg(v24, __ T2D, v25); // fneg v24.2D, v25.2D + __ fsqrt(v4, __ T2S, v5); // fsqrt v4.2S, v5.2S + __ fsqrt(v3, __ T4S, v4); // fsqrt v3.4S, v4.4S + __ fsqrt(v12, __ T2D, v13); // fsqrt v12.2D, v13.2D + __ notr(v31, __ T8B, v0); // not v31.8B, v0.8B + __ notr(v28, __ T16B, v29); // not v28.16B, v29.16B // ThreeRegNEONOp - __ andr(v19, __ T8B, v20, v21); // and v19.8B, v20.8B, v21.8B - __ andr(v22, __ T16B, v23, v24); // and v22.16B, v23.16B, v24.16B - __ orr(v10, __ T8B, v11, v12); // orr v10.8B, v11.8B, v12.8B - __ orr(v4, __ T16B, v5, v6); // orr v4.16B, v5.16B, v6.16B - __ eor(v31, __ T8B, v0, v1); // eor v31.8B, v0.8B, v1.8B - __ eor(v21, __ T16B, v22, v23); // eor v21.16B, v22.16B, v23.16B - __ addv(v8, __ T8B, v9, v10); // add v8.8B, v9.8B, v10.8B - __ addv(v31, __ T16B, v0, v1); // add v31.16B, v0.16B, v1.16B - __ addv(v19, __ T4H, v20, v21); // add v19.4H, v20.4H, v21.4H - __ addv(v10, __ T8H, v11, v12); // add v10.8H, v11.8H, v12.8H - __ addv(v28, __ T2S, v29, v30); // add v28.2S, v29.2S, v30.2S - __ addv(v2, __ T4S, v3, v4); // add v2.4S, v3.4S, v4.4S - __ addv(v25, __ T2D, v26, v27); // add v25.2D, v26.2D, v27.2D - __ sqaddv(v5, __ T8B, v6, v7); // sqadd v5.8B, v6.8B, v7.8B - __ sqaddv(v3, __ T16B, v4, v5); // sqadd v3.16B, v4.16B, v5.16B - __ sqaddv(v8, __ T4H, v9, v10); // sqadd v8.4H, v9.4H, v10.4H - __ sqaddv(v22, __ T8H, v23, v24); // sqadd v22.8H, v23.8H, v24.8H - __ sqaddv(v19, __ T2S, v20, v21); // sqadd v19.2S, v20.2S, v21.2S - __ sqaddv(v13, __ T4S, v14, v15); // sqadd v13.4S, v14.4S, v15.4S - __ sqaddv(v5, __ T2D, v6, v7); // sqadd v5.2D, v6.2D, v7.2D - __ uqaddv(v29, __ T8B, v30, v31); // uqadd v29.8B, v30.8B, v31.8B - __ uqaddv(v24, __ T16B, v25, v26); // uqadd v24.16B, v25.16B, v26.16B - __ uqaddv(v21, __ T4H, v22, v23); // uqadd v21.4H, v22.4H, v23.4H - __ uqaddv(v26, __ T8H, v27, v28); // uqadd v26.8H, v27.8H, v28.8H - __ uqaddv(v24, __ T2S, v25, v26); // uqadd v24.2S, v25.2S, v26.2S - __ uqaddv(v3, __ T4S, v4, v5); // uqadd v3.4S, v4.4S, v5.4S - __ uqaddv(v24, __ T2D, v25, v26); // uqadd v24.2D, v25.2D, v26.2D - __ fadd(v26, __ T2S, v27, v28); // fadd v26.2S, v27.2S, v28.2S - __ fadd(v23, __ T4S, v24, v25); // fadd v23.4S, v24.4S, v25.4S - __ fadd(v15, __ T2D, v16, v17); // fadd v15.2D, v16.2D, v17.2D - __ subv(v21, __ T8B, v22, v23); // sub v21.8B, v22.8B, v23.8B - __ subv(v3, __ T16B, v4, v5); // sub v3.16B, v4.16B, v5.16B - __ subv(v24, __ T4H, v25, v26); // sub v24.4H, v25.4H, v26.4H - __ subv(v8, __ T8H, v9, v10); // sub v8.8H, v9.8H, v10.8H - __ subv(v25, __ T2S, v26, v27); // sub v25.2S, v26.2S, v27.2S - __ subv(v20, __ T4S, v21, v22); // sub v20.4S, v21.4S, v22.4S - __ subv(v16, __ T2D, v17, v18); // sub v16.2D, v17.2D, v18.2D - __ sqsubv(v17, __ T8B, v18, v19); // sqsub v17.8B, v18.8B, v19.8B - __ sqsubv(v2, __ T16B, v3, v4); // sqsub v2.16B, v3.16B, v4.16B - __ sqsubv(v1, __ T4H, v2, v3); // sqsub v1.4H, v2.4H, v3.4H - __ sqsubv(v0, __ T8H, v1, v2); // sqsub v0.8H, v1.8H, v2.8H - __ sqsubv(v24, __ T2S, v25, v26); // sqsub v24.2S, v25.2S, v26.2S - __ sqsubv(v4, __ T4S, v5, v6); // sqsub v4.4S, v5.4S, v6.4S - __ sqsubv(v3, __ T2D, v4, v5); // sqsub v3.2D, v4.2D, v5.2D - __ uqsubv(v12, __ T8B, v13, v14); // uqsub v12.8B, v13.8B, v14.8B - __ uqsubv(v31, __ T16B, v0, v1); // uqsub v31.16B, v0.16B, v1.16B - __ uqsubv(v28, __ T4H, v29, v30); // uqsub v28.4H, v29.4H, v30.4H - __ uqsubv(v10, __ T8H, v11, v12); // uqsub v10.8H, v11.8H, v12.8H - __ uqsubv(v26, __ T2S, v27, v28); // uqsub v26.2S, v27.2S, v28.2S - __ uqsubv(v2, __ T4S, v3, v4); // uqsub v2.4S, v3.4S, v4.4S - __ uqsubv(v12, __ T2D, v13, v14); // uqsub v12.2D, v13.2D, v14.2D - __ fsub(v18, __ T2S, v19, v20); // fsub v18.2S, v19.2S, v20.2S - __ fsub(v31, __ T4S, v0, v1); // fsub v31.4S, v0.4S, v1.4S - __ fsub(v1, __ T2D, v2, v3); // fsub v1.2D, v2.2D, v3.2D - __ mulv(v13, __ T8B, v14, v15); // mul v13.8B, v14.8B, v15.8B - __ mulv(v29, __ T16B, v30, v31); // mul v29.16B, v30.16B, v31.16B - __ mulv(v0, __ T4H, v1, v2); // mul v0.4H, v1.4H, v2.4H - __ mulv(v19, __ T8H, v20, v21); // mul v19.8H, v20.8H, v21.8H - __ mulv(v12, __ T2S, v13, v14); // mul v12.2S, v13.2S, v14.2S - __ mulv(v17, __ T4S, v18, v19); // mul v17.4S, v18.4S, v19.4S - __ fabd(v22, __ T2S, v23, v24); // fabd v22.2S, v23.2S, v24.2S - __ fabd(v13, __ T4S, v14, v15); // fabd v13.4S, v14.4S, v15.4S - __ fabd(v28, __ T2D, v29, v30); // fabd v28.2D, v29.2D, v30.2D - __ faddp(v30, __ T2S, v31, v0); // faddp v30.2S, v31.2S, v0.2S - __ faddp(v31, __ T4S, v0, v1); // faddp v31.4S, v0.4S, v1.4S - __ faddp(v1, __ T2D, v2, v3); // faddp v1.2D, v2.2D, v3.2D - __ fmul(v26, __ T2S, v27, v28); // fmul v26.2S, v27.2S, v28.2S - __ fmul(v28, __ T4S, v29, v30); // fmul v28.4S, v29.4S, v30.4S - __ fmul(v4, __ T2D, v5, v6); // fmul v4.2D, v5.2D, v6.2D - __ mlav(v30, __ T4H, v31, v0); // mla v30.4H, v31.4H, v0.4H - __ mlav(v4, __ T8H, v5, v6); // mla v4.8H, v5.8H, v6.8H - __ mlav(v6, __ T2S, v7, v8); // mla v6.2S, v7.2S, v8.2S - __ mlav(v30, __ T4S, v31, v0); // mla v30.4S, v31.4S, v0.4S - __ fmla(v26, __ T2S, v27, v28); // fmla v26.2S, v27.2S, v28.2S - __ fmla(v18, __ T4S, v19, v20); // fmla v18.4S, v19.4S, v20.4S - __ fmla(v9, __ T2D, v10, v11); // fmla v9.2D, v10.2D, v11.2D - __ mlsv(v8, __ T4H, v9, v10); // mls v8.4H, v9.4H, v10.4H - __ mlsv(v12, __ T8H, v13, v14); // mls v12.8H, v13.8H, v14.8H - __ mlsv(v0, __ T2S, v1, v2); // mls v0.2S, v1.2S, v2.2S - __ mlsv(v20, __ T4S, v21, v22); // mls v20.4S, v21.4S, v22.4S - __ fmls(v1, __ T2S, v2, v3); // fmls v1.2S, v2.2S, v3.2S - __ fmls(v24, __ T4S, v25, v26); // fmls v24.4S, v25.4S, v26.4S - __ fmls(v2, __ T2D, v3, v4); // fmls v2.2D, v3.2D, v4.2D - __ fdiv(v0, __ T2S, v1, v2); // fdiv v0.2S, v1.2S, v2.2S - __ fdiv(v9, __ T4S, v10, v11); // fdiv v9.4S, v10.4S, v11.4S - __ fdiv(v24, __ T2D, v25, v26); // fdiv v24.2D, v25.2D, v26.2D - __ maxv(v26, __ T8B, v27, v28); // smax v26.8B, v27.8B, v28.8B + __ andr(v10, __ T8B, v11, v12); // and v10.8B, v11.8B, v12.8B + __ andr(v26, __ T16B, v27, v28); // and v26.16B, v27.16B, v28.16B + __ orr(v2, __ T8B, v3, v4); // orr v2.8B, v3.8B, v4.8B + __ orr(v12, __ T16B, v13, v14); // orr v12.16B, v13.16B, v14.16B + __ eor(v18, __ T8B, v19, v20); // eor v18.8B, v19.8B, v20.8B + __ eor(v31, __ T16B, v0, v1); // eor v31.16B, v0.16B, v1.16B + __ addv(v1, __ T8B, v2, v3); // add v1.8B, v2.8B, v3.8B + __ addv(v13, __ T16B, v14, v15); // add v13.16B, v14.16B, v15.16B + __ addv(v29, __ T4H, v30, v31); // add v29.4H, v30.4H, v31.4H + __ addv(v0, __ T8H, v1, v2); // add v0.8H, v1.8H, v2.8H + __ addv(v19, __ T2S, v20, v21); // add v19.2S, v20.2S, v21.2S + __ addv(v12, __ T4S, v13, v14); // add v12.4S, v13.4S, v14.4S + __ addv(v17, __ T2D, v18, v19); // add v17.2D, v18.2D, v19.2D + __ sqaddv(v22, __ T8B, v23, v24); // sqadd v22.8B, v23.8B, v24.8B + __ sqaddv(v13, __ T16B, v14, v15); // sqadd v13.16B, v14.16B, v15.16B + __ sqaddv(v28, __ T4H, v29, v30); // sqadd v28.4H, v29.4H, v30.4H + __ sqaddv(v30, __ T8H, v31, v0); // sqadd v30.8H, v31.8H, v0.8H + __ sqaddv(v31, __ T2S, v0, v1); // sqadd v31.2S, v0.2S, v1.2S + __ sqaddv(v1, __ T4S, v2, v3); // sqadd v1.4S, v2.4S, v3.4S + __ sqaddv(v26, __ T2D, v27, v28); // sqadd v26.2D, v27.2D, v28.2D + __ uqaddv(v28, __ T8B, v29, v30); // uqadd v28.8B, v29.8B, v30.8B + __ uqaddv(v4, __ T16B, v5, v6); // uqadd v4.16B, v5.16B, v6.16B + __ uqaddv(v30, __ T4H, v31, v0); // uqadd v30.4H, v31.4H, v0.4H + __ uqaddv(v4, __ T8H, v5, v6); // uqadd v4.8H, v5.8H, v6.8H + __ uqaddv(v6, __ T2S, v7, v8); // uqadd v6.2S, v7.2S, v8.2S + __ uqaddv(v30, __ T4S, v31, v0); // uqadd v30.4S, v31.4S, v0.4S + __ uqaddv(v26, __ T2D, v27, v28); // uqadd v26.2D, v27.2D, v28.2D + __ fadd(v18, __ T2S, v19, v20); // fadd v18.2S, v19.2S, v20.2S + __ fadd(v9, __ T4S, v10, v11); // fadd v9.4S, v10.4S, v11.4S + __ fadd(v8, __ T2D, v9, v10); // fadd v8.2D, v9.2D, v10.2D + __ subv(v12, __ T8B, v13, v14); // sub v12.8B, v13.8B, v14.8B + __ subv(v0, __ T16B, v1, v2); // sub v0.16B, v1.16B, v2.16B + __ subv(v20, __ T4H, v21, v22); // sub v20.4H, v21.4H, v22.4H + __ subv(v1, __ T8H, v2, v3); // sub v1.8H, v2.8H, v3.8H + __ subv(v24, __ T2S, v25, v26); // sub v24.2S, v25.2S, v26.2S + __ subv(v2, __ T4S, v3, v4); // sub v2.4S, v3.4S, v4.4S + __ subv(v0, __ T2D, v1, v2); // sub v0.2D, v1.2D, v2.2D + __ sqsubv(v9, __ T8B, v10, v11); // sqsub v9.8B, v10.8B, v11.8B + __ sqsubv(v24, __ T16B, v25, v26); // sqsub v24.16B, v25.16B, v26.16B + __ sqsubv(v26, __ T4H, v27, v28); // sqsub v26.4H, v27.4H, v28.4H + __ sqsubv(v16, __ T8H, v17, v18); // sqsub v16.8H, v17.8H, v18.8H + __ sqsubv(v30, __ T2S, v31, v0); // sqsub v30.2S, v31.2S, v0.2S + __ sqsubv(v3, __ T4S, v4, v5); // sqsub v3.4S, v4.4S, v5.4S + __ sqsubv(v10, __ T2D, v11, v12); // sqsub v10.2D, v11.2D, v12.2D + __ uqsubv(v23, __ T8B, v24, v25); // uqsub v23.8B, v24.8B, v25.8B + __ uqsubv(v10, __ T16B, v11, v12); // uqsub v10.16B, v11.16B, v12.16B + __ uqsubv(v4, __ T4H, v5, v6); // uqsub v4.4H, v5.4H, v6.4H + __ uqsubv(v18, __ T8H, v19, v20); // uqsub v18.8H, v19.8H, v20.8H + __ uqsubv(v2, __ T2S, v3, v4); // uqsub v2.2S, v3.2S, v4.2S + __ uqsubv(v11, __ T4S, v12, v13); // uqsub v11.4S, v12.4S, v13.4S + __ uqsubv(v8, __ T2D, v9, v10); // uqsub v8.2D, v9.2D, v10.2D + __ fsub(v10, __ T2S, v11, v12); // fsub v10.2S, v11.2S, v12.2S + __ fsub(v15, __ T4S, v16, v17); // fsub v15.4S, v16.4S, v17.4S + __ fsub(v17, __ T2D, v18, v19); // fsub v17.2D, v18.2D, v19.2D + __ mulv(v2, __ T8B, v3, v4); // mul v2.8B, v3.8B, v4.8B + __ mulv(v10, __ T16B, v11, v12); // mul v10.16B, v11.16B, v12.16B + __ mulv(v12, __ T4H, v13, v14); // mul v12.4H, v13.4H, v14.4H + __ mulv(v12, __ T8H, v13, v14); // mul v12.8H, v13.8H, v14.8H + __ mulv(v15, __ T2S, v16, v17); // mul v15.2S, v16.2S, v17.2S + __ mulv(v13, __ T4S, v14, v15); // mul v13.4S, v14.4S, v15.4S + __ fabd(v2, __ T2S, v3, v4); // fabd v2.2S, v3.2S, v4.2S + __ fabd(v7, __ T4S, v8, v9); // fabd v7.4S, v8.4S, v9.4S + __ fabd(v20, __ T2D, v21, v22); // fabd v20.2D, v21.2D, v22.2D + __ faddp(v26, __ T2S, v27, v28); // faddp v26.2S, v27.2S, v28.2S + __ faddp(v16, __ T4S, v17, v18); // faddp v16.4S, v17.4S, v18.4S + __ faddp(v4, __ T2D, v5, v6); // faddp v4.2D, v5.2D, v6.2D + __ fmul(v2, __ T2S, v3, v4); // fmul v2.2S, v3.2S, v4.2S + __ fmul(v4, __ T4S, v5, v6); // fmul v4.4S, v5.4S, v6.4S + __ fmul(v12, __ T2D, v13, v14); // fmul v12.2D, v13.2D, v14.2D + __ mlav(v18, __ T4H, v19, v20); // mla v18.4H, v19.4H, v20.4H + __ mlav(v21, __ T8H, v22, v23); // mla v21.8H, v22.8H, v23.8H + __ mlav(v16, __ T2S, v17, v18); // mla v16.2S, v17.2S, v18.2S + __ mlav(v18, __ T4S, v19, v20); // mla v18.4S, v19.4S, v20.4S + __ fmla(v11, __ T2S, v12, v13); // fmla v11.2S, v12.2S, v13.2S + __ fmla(v21, __ T4S, v22, v23); // fmla v21.4S, v22.4S, v23.4S + __ fmla(v23, __ T2D, v24, v25); // fmla v23.2D, v24.2D, v25.2D + __ mlsv(v12, __ T4H, v13, v14); // mls v12.4H, v13.4H, v14.4H + __ mlsv(v26, __ T8H, v27, v28); // mls v26.8H, v27.8H, v28.8H + __ mlsv(v23, __ T2S, v24, v25); // mls v23.2S, v24.2S, v25.2S + __ mlsv(v28, __ T4S, v29, v30); // mls v28.4S, v29.4S, v30.4S + __ fmls(v14, __ T2S, v15, v16); // fmls v14.2S, v15.2S, v16.2S + __ fmls(v11, __ T4S, v12, v13); // fmls v11.4S, v12.4S, v13.4S + __ fmls(v24, __ T2D, v25, v26); // fmls v24.2D, v25.2D, v26.2D + __ fdiv(v1, __ T2S, v2, v3); // fdiv v1.2S, v2.2S, v3.2S + __ fdiv(v12, __ T4S, v13, v14); // fdiv v12.4S, v13.4S, v14.4S + __ fdiv(v31, __ T2D, v0, v1); // fdiv v31.2D, v0.2D, v1.2D + __ maxv(v10, __ T8B, v11, v12); // smax v10.8B, v11.8B, v12.8B __ maxv(v16, __ T16B, v17, v18); // smax v16.16B, v17.16B, v18.16B - __ maxv(v30, __ T4H, v31, v0); // smax v30.4H, v31.4H, v0.4H - __ maxv(v3, __ T8H, v4, v5); // smax v3.8H, v4.8H, v5.8H - __ maxv(v10, __ T2S, v11, v12); // smax v10.2S, v11.2S, v12.2S - __ maxv(v23, __ T4S, v24, v25); // smax v23.4S, v24.4S, v25.4S - __ umaxv(v10, __ T8B, v11, v12); // umax v10.8B, v11.8B, v12.8B - __ umaxv(v4, __ T16B, v5, v6); // umax v4.16B, v5.16B, v6.16B - __ umaxv(v18, __ T4H, v19, v20); // umax v18.4H, v19.4H, v20.4H - __ umaxv(v2, __ T8H, v3, v4); // umax v2.8H, v3.8H, v4.8H - __ umaxv(v11, __ T2S, v12, v13); // umax v11.2S, v12.2S, v13.2S - __ umaxv(v8, __ T4S, v9, v10); // umax v8.4S, v9.4S, v10.4S - __ smaxp(v10, __ T8B, v11, v12); // smaxp v10.8B, v11.8B, v12.8B - __ smaxp(v15, __ T16B, v16, v17); // smaxp v15.16B, v16.16B, v17.16B - __ smaxp(v17, __ T4H, v18, v19); // smaxp v17.4H, v18.4H, v19.4H - __ smaxp(v2, __ T8H, v3, v4); // smaxp v2.8H, v3.8H, v4.8H - __ smaxp(v10, __ T2S, v11, v12); // smaxp v10.2S, v11.2S, v12.2S - __ smaxp(v12, __ T4S, v13, v14); // smaxp v12.4S, v13.4S, v14.4S - __ fmax(v12, __ T2S, v13, v14); // fmax v12.2S, v13.2S, v14.2S - __ fmax(v15, __ T4S, v16, v17); // fmax v15.4S, v16.4S, v17.4S - __ fmax(v13, __ T2D, v14, v15); // fmax v13.2D, v14.2D, v15.2D - __ minv(v2, __ T8B, v3, v4); // smin v2.8B, v3.8B, v4.8B - __ minv(v7, __ T16B, v8, v9); // smin v7.16B, v8.16B, v9.16B - __ minv(v20, __ T4H, v21, v22); // smin v20.4H, v21.4H, v22.4H - __ minv(v26, __ T8H, v27, v28); // smin v26.8H, v27.8H, v28.8H - __ minv(v16, __ T2S, v17, v18); // smin v16.2S, v17.2S, v18.2S - __ minv(v4, __ T4S, v5, v6); // smin v4.4S, v5.4S, v6.4S - __ uminv(v2, __ T8B, v3, v4); // umin v2.8B, v3.8B, v4.8B - __ uminv(v4, __ T16B, v5, v6); // umin v4.16B, v5.16B, v6.16B - __ uminv(v12, __ T4H, v13, v14); // umin v12.4H, v13.4H, v14.4H - __ uminv(v18, __ T8H, v19, v20); // umin v18.8H, v19.8H, v20.8H - __ uminv(v21, __ T2S, v22, v23); // umin v21.2S, v22.2S, v23.2S - __ uminv(v16, __ T4S, v17, v18); // umin v16.4S, v17.4S, v18.4S - __ sminp(v18, __ T8B, v19, v20); // sminp v18.8B, v19.8B, v20.8B - __ sminp(v11, __ T16B, v12, v13); // sminp v11.16B, v12.16B, v13.16B - __ sminp(v21, __ T4H, v22, v23); // sminp v21.4H, v22.4H, v23.4H - __ sminp(v23, __ T8H, v24, v25); // sminp v23.8H, v24.8H, v25.8H - __ sminp(v12, __ T2S, v13, v14); // sminp v12.2S, v13.2S, v14.2S - __ sminp(v26, __ T4S, v27, v28); // sminp v26.4S, v27.4S, v28.4S - __ sqdmulh(v23, __ T4H, v24, v25); // sqdmulh v23.4H, v24.4H, v25.4H - __ sqdmulh(v28, __ T8H, v29, v30); // sqdmulh v28.8H, v29.8H, v30.8H - __ sqdmulh(v14, __ T2S, v15, v16); // sqdmulh v14.2S, v15.2S, v16.2S - __ sqdmulh(v11, __ T4S, v12, v13); // sqdmulh v11.4S, v12.4S, v13.4S - __ shsubv(v24, __ T8B, v25, v26); // shsub v24.8B, v25.8B, v26.8B - __ shsubv(v1, __ T16B, v2, v3); // shsub v1.16B, v2.16B, v3.16B - __ shsubv(v12, __ T4H, v13, v14); // shsub v12.4H, v13.4H, v14.4H - __ shsubv(v31, __ T8H, v0, v1); // shsub v31.8H, v0.8H, v1.8H - __ shsubv(v10, __ T2S, v11, v12); // shsub v10.2S, v11.2S, v12.2S - __ shsubv(v16, __ T4S, v17, v18); // shsub v16.4S, v17.4S, v18.4S - __ fmin(v7, __ T2S, v8, v9); // fmin v7.2S, v8.2S, v9.2S - __ fmin(v2, __ T4S, v3, v4); // fmin v2.4S, v3.4S, v4.4S - __ fmin(v3, __ T2D, v4, v5); // fmin v3.2D, v4.2D, v5.2D - __ facgt(v13, __ T2S, v14, v15); // facgt v13.2S, v14.2S, v15.2S - __ facgt(v19, __ T4S, v20, v21); // facgt v19.4S, v20.4S, v21.4S - __ facgt(v17, __ T2D, v18, v19); // facgt v17.2D, v18.2D, v19.2D + __ maxv(v7, __ T4H, v8, v9); // smax v7.4H, v8.4H, v9.4H + __ maxv(v2, __ T8H, v3, v4); // smax v2.8H, v3.8H, v4.8H + __ maxv(v3, __ T2S, v4, v5); // smax v3.2S, v4.2S, v5.2S + __ maxv(v13, __ T4S, v14, v15); // smax v13.4S, v14.4S, v15.4S + __ umaxv(v19, __ T8B, v20, v21); // umax v19.8B, v20.8B, v21.8B + __ umaxv(v17, __ T16B, v18, v19); // umax v17.16B, v18.16B, v19.16B + __ umaxv(v16, __ T4H, v17, v18); // umax v16.4H, v17.4H, v18.4H + __ umaxv(v3, __ T8H, v4, v5); // umax v3.8H, v4.8H, v5.8H + __ umaxv(v1, __ T2S, v2, v3); // umax v1.2S, v2.2S, v3.2S + __ umaxv(v11, __ T4S, v12, v13); // umax v11.4S, v12.4S, v13.4S + __ smaxp(v30, __ T8B, v31, v0); // smaxp v30.8B, v31.8B, v0.8B + __ smaxp(v5, __ T16B, v6, v7); // smaxp v5.16B, v6.16B, v7.16B + __ smaxp(v8, __ T4H, v9, v10); // smaxp v8.4H, v9.4H, v10.4H + __ smaxp(v15, __ T8H, v16, v17); // smaxp v15.8H, v16.8H, v17.8H + __ smaxp(v29, __ T2S, v30, v31); // smaxp v29.2S, v30.2S, v31.2S + __ smaxp(v30, __ T4S, v31, v0); // smaxp v30.4S, v31.4S, v0.4S + __ fmax(v0, __ T2S, v1, v2); // fmax v0.2S, v1.2S, v2.2S + __ fmax(v20, __ T4S, v21, v22); // fmax v20.4S, v21.4S, v22.4S + __ fmax(v7, __ T2D, v8, v9); // fmax v7.2D, v8.2D, v9.2D + __ minv(v20, __ T8B, v21, v22); // smin v20.8B, v21.8B, v22.8B + __ minv(v23, __ T16B, v24, v25); // smin v23.16B, v24.16B, v25.16B + __ minv(v28, __ T4H, v29, v30); // smin v28.4H, v29.4H, v30.4H + __ minv(v21, __ T8H, v22, v23); // smin v21.8H, v22.8H, v23.8H + __ minv(v27, __ T2S, v28, v29); // smin v27.2S, v28.2S, v29.2S + __ minv(v25, __ T4S, v26, v27); // smin v25.4S, v26.4S, v27.4S + __ uminv(v5, __ T8B, v6, v7); // umin v5.8B, v6.8B, v7.8B + __ uminv(v1, __ T16B, v2, v3); // umin v1.16B, v2.16B, v3.16B + __ uminv(v23, __ T4H, v24, v25); // umin v23.4H, v24.4H, v25.4H + __ uminv(v16, __ T8H, v17, v18); // umin v16.8H, v17.8H, v18.8H + __ uminv(v31, __ T2S, v0, v1); // umin v31.2S, v0.2S, v1.2S + __ uminv(v5, __ T4S, v6, v7); // umin v5.4S, v6.4S, v7.4S + __ sminp(v12, __ T8B, v13, v14); // sminp v12.8B, v13.8B, v14.8B + __ sminp(v9, __ T16B, v10, v11); // sminp v9.16B, v10.16B, v11.16B + __ sminp(v28, __ T4H, v29, v30); // sminp v28.4H, v29.4H, v30.4H + __ sminp(v15, __ T8H, v16, v17); // sminp v15.8H, v16.8H, v17.8H + __ sminp(v29, __ T2S, v30, v31); // sminp v29.2S, v30.2S, v31.2S + __ sminp(v22, __ T4S, v23, v24); // sminp v22.4S, v23.4S, v24.4S + __ sqdmulh(v31, __ T4H, v0, v1); // sqdmulh v31.4H, v0.4H, v1.4H + __ sqdmulh(v19, __ T8H, v20, v21); // sqdmulh v19.8H, v20.8H, v21.8H + __ sqdmulh(v31, __ T2S, v0, v1); // sqdmulh v31.2S, v0.2S, v1.2S + __ sqdmulh(v5, __ T4S, v6, v7); // sqdmulh v5.4S, v6.4S, v7.4S + __ shsubv(v14, __ T8B, v15, v16); // shsub v14.8B, v15.8B, v16.8B + __ shsubv(v18, __ T16B, v19, v20); // shsub v18.16B, v19.16B, v20.16B + __ shsubv(v31, __ T4H, v0, v1); // shsub v31.4H, v0.4H, v1.4H + __ shsubv(v18, __ T8H, v19, v20); // shsub v18.8H, v19.8H, v20.8H + __ shsubv(v27, __ T2S, v28, v29); // shsub v27.2S, v28.2S, v29.2S + __ shsubv(v20, __ T4S, v21, v22); // shsub v20.4S, v21.4S, v22.4S + __ fmin(v16, __ T2S, v17, v18); // fmin v16.2S, v17.2S, v18.2S + __ fmin(v12, __ T4S, v13, v14); // fmin v12.4S, v13.4S, v14.4S + __ fmin(v11, __ T2D, v12, v13); // fmin v11.2D, v12.2D, v13.2D + __ facgt(v9, __ T2S, v10, v11); // facgt v9.2S, v10.2S, v11.2S + __ facgt(v6, __ T4S, v7, v8); // facgt v6.4S, v7.4S, v8.4S + __ facgt(v30, __ T2D, v31, v0); // facgt v30.2D, v31.2D, v0.2D // VectorScalarNEONInstruction - __ fmlavs(v1, __ T2S, v2, v3, 1); // fmla v1.2S, v2.2S, v3.S[1] - __ mulvs(v5, __ T4S, v6, v7, 0); // mul v5.4S, v6.4S, v7.S[0] - __ fmlavs(v2, __ T2D, v3, v4, 1); // fmla v2.2D, v3.2D, v4.D[1] - __ fmlsvs(v7, __ T2S, v8, v9, 0); // fmls v7.2S, v8.2S, v9.S[0] + __ fmlavs(v13, __ T2S, v14, v15, 1); // fmla v13.2S, v14.2S, v15.S[1] __ mulvs(v15, __ T4S, v0, v1, 3); // mul v15.4S, v0.4S, v1.S[3] - __ fmlsvs(v10, __ T2D, v11, v12, 0); // fmls v10.2D, v11.2D, v12.D[0] - __ fmulxvs(v10, __ T2S, v11, v12, 0); // fmulx v10.2S, v11.2S, v12.S[0] - __ mulvs(v14, __ T4S, v15, v16, 2); // mul v14.4S, v15.4S, v16.S[2] - __ fmulxvs(v13, __ T2D, v14, v15, 1); // fmulx v13.2D, v14.2D, v15.D[1] - __ mulvs(v2, __ T4H, v3, v4, 3); // mul v2.4H, v3.4H, v4.H[3] - __ mulvs(v11, __ T8H, v12, v13, 0); // mul v11.8H, v12.8H, v13.H[0] - __ mulvs(v15, __ T2S, v0, v1, 1); // mul v15.2S, v0.2S, v1.S[1] - __ mulvs(v6, __ T4S, v7, v8, 0); // mul v6.4S, v7.4S, v8.S[0] + __ fmlavs(v5, __ T2D, v6, v7, 0); // fmla v5.2D, v6.2D, v7.D[0] + __ fmlsvs(v5, __ T2S, v6, v7, 1); // fmls v5.2S, v6.2S, v7.S[1] + __ mulvs(v12, __ T4S, v13, v14, 0); // mul v12.4S, v13.4S, v14.S[0] + __ fmlsvs(v8, __ T2D, v9, v10, 1); // fmls v8.2D, v9.2D, v10.D[1] + __ fmulxvs(v1, __ T2S, v2, v3, 1); // fmulx v1.2S, v2.2S, v3.S[1] + __ mulvs(v7, __ T4S, v8, v9, 3); // mul v7.4S, v8.4S, v9.S[3] + __ fmulxvs(v9, __ T2D, v10, v11, 1); // fmulx v9.2D, v10.2D, v11.D[1] + __ mulvs(v11, __ T4H, v12, v13, 2); // mul v11.4H, v12.4H, v13.H[2] + __ mulvs(v7, __ T8H, v8, v9, 0); // mul v7.8H, v8.8H, v9.H[0] + __ mulvs(v6, __ T2S, v7, v8, 0); // mul v6.2S, v7.2S, v8.S[0] + __ mulvs(v5, __ T4S, v6, v7, 2); // mul v5.4S, v6.4S, v7.S[2] // NEONVectorCompare - __ cm(Assembler::GT, v9, __ T8B, v10, v11); // cmgt v9.8B, v10.8B, v11.8B - __ cm(Assembler::GT, v28, __ T16B, v29, v30); // cmgt v28.16B, v29.16B, v30.16B - __ cm(Assembler::GT, v15, __ T4H, v16, v17); // cmgt v15.4H, v16.4H, v17.4H - __ cm(Assembler::GT, v29, __ T8H, v30, v31); // cmgt v29.8H, v30.8H, v31.8H - __ cm(Assembler::GT, v22, __ T2S, v23, v24); // cmgt v22.2S, v23.2S, v24.2S - __ cm(Assembler::GT, v31, __ T4S, v0, v1); // cmgt v31.4S, v0.4S, v1.4S - __ cm(Assembler::GT, v19, __ T2D, v20, v21); // cmgt v19.2D, v20.2D, v21.2D - __ cm(Assembler::GE, v31, __ T8B, v0, v1); // cmge v31.8B, v0.8B, v1.8B - __ cm(Assembler::GE, v5, __ T16B, v6, v7); // cmge v5.16B, v6.16B, v7.16B - __ cm(Assembler::GE, v14, __ T4H, v15, v16); // cmge v14.4H, v15.4H, v16.4H - __ cm(Assembler::GE, v18, __ T8H, v19, v20); // cmge v18.8H, v19.8H, v20.8H - __ cm(Assembler::GE, v31, __ T2S, v0, v1); // cmge v31.2S, v0.2S, v1.2S - __ cm(Assembler::GE, v18, __ T4S, v19, v20); // cmge v18.4S, v19.4S, v20.4S - __ cm(Assembler::GE, v27, __ T2D, v28, v29); // cmge v27.2D, v28.2D, v29.2D - __ cm(Assembler::EQ, v20, __ T8B, v21, v22); // cmeq v20.8B, v21.8B, v22.8B - __ cm(Assembler::EQ, v16, __ T16B, v17, v18); // cmeq v16.16B, v17.16B, v18.16B - __ cm(Assembler::EQ, v12, __ T4H, v13, v14); // cmeq v12.4H, v13.4H, v14.4H - __ cm(Assembler::EQ, v11, __ T8H, v12, v13); // cmeq v11.8H, v12.8H, v13.8H - __ cm(Assembler::EQ, v9, __ T2S, v10, v11); // cmeq v9.2S, v10.2S, v11.2S - __ cm(Assembler::EQ, v6, __ T4S, v7, v8); // cmeq v6.4S, v7.4S, v8.4S - __ cm(Assembler::EQ, v30, __ T2D, v31, v0); // cmeq v30.2D, v31.2D, v0.2D - __ cm(Assembler::HI, v17, __ T8B, v18, v19); // cmhi v17.8B, v18.8B, v19.8B - __ cm(Assembler::HI, v27, __ T16B, v28, v29); // cmhi v27.16B, v28.16B, v29.16B - __ cm(Assembler::HI, v28, __ T4H, v29, v30); // cmhi v28.4H, v29.4H, v30.4H - __ cm(Assembler::HI, v30, __ T8H, v31, v0); // cmhi v30.8H, v31.8H, v0.8H - __ cm(Assembler::HI, v7, __ T2S, v8, v9); // cmhi v7.2S, v8.2S, v9.2S - __ cm(Assembler::HI, v10, __ T4S, v11, v12); // cmhi v10.4S, v11.4S, v12.4S - __ cm(Assembler::HI, v20, __ T2D, v21, v22); // cmhi v20.2D, v21.2D, v22.2D - __ cm(Assembler::HS, v10, __ T8B, v11, v12); // cmhs v10.8B, v11.8B, v12.8B - __ cm(Assembler::HS, v4, __ T16B, v5, v6); // cmhs v4.16B, v5.16B, v6.16B - __ cm(Assembler::HS, v24, __ T4H, v25, v26); // cmhs v24.4H, v25.4H, v26.4H - __ cm(Assembler::HS, v17, __ T8H, v18, v19); // cmhs v17.8H, v18.8H, v19.8H - __ cm(Assembler::HS, v17, __ T2S, v18, v19); // cmhs v17.2S, v18.2S, v19.2S - __ cm(Assembler::HS, v22, __ T4S, v23, v24); // cmhs v22.4S, v23.4S, v24.4S - __ cm(Assembler::HS, v3, __ T2D, v4, v5); // cmhs v3.2D, v4.2D, v5.2D - __ fcm(Assembler::EQ, v29, __ T2S, v30, v31); // fcmeq v29.2S, v30.2S, v31.2S - __ fcm(Assembler::EQ, v15, __ T4S, v16, v17); // fcmeq v15.4S, v16.4S, v17.4S - __ fcm(Assembler::EQ, v22, __ T2D, v23, v24); // fcmeq v22.2D, v23.2D, v24.2D + __ cm(Assembler::GT, v13, __ T8B, v14, v15); // cmgt v13.8B, v14.8B, v15.8B + __ cm(Assembler::GT, v23, __ T16B, v24, v25); // cmgt v23.16B, v24.16B, v25.16B + __ cm(Assembler::GT, v1, __ T4H, v2, v3); // cmgt v1.4H, v2.4H, v3.4H + __ cm(Assembler::GT, v30, __ T8H, v31, v0); // cmgt v30.8H, v31.8H, v0.8H + __ cm(Assembler::GT, v19, __ T2S, v20, v21); // cmgt v19.2S, v20.2S, v21.2S + __ cm(Assembler::GT, v5, __ T4S, v6, v7); // cmgt v5.4S, v6.4S, v7.4S + __ cm(Assembler::GT, v17, __ T2D, v18, v19); // cmgt v17.2D, v18.2D, v19.2D + __ cm(Assembler::GE, v2, __ T8B, v3, v4); // cmge v2.8B, v3.8B, v4.8B + __ cm(Assembler::GE, v16, __ T16B, v17, v18); // cmge v16.16B, v17.16B, v18.16B + __ cm(Assembler::GE, v22, __ T4H, v23, v24); // cmge v22.4H, v23.4H, v24.4H + __ cm(Assembler::GE, v13, __ T8H, v14, v15); // cmge v13.8H, v14.8H, v15.8H + __ cm(Assembler::GE, v10, __ T2S, v11, v12); // cmge v10.2S, v11.2S, v12.2S + __ cm(Assembler::GE, v21, __ T4S, v22, v23); // cmge v21.4S, v22.4S, v23.4S + __ cm(Assembler::GE, v29, __ T2D, v30, v31); // cmge v29.2D, v30.2D, v31.2D + __ cm(Assembler::EQ, v27, __ T8B, v28, v29); // cmeq v27.8B, v28.8B, v29.8B + __ cm(Assembler::EQ, v12, __ T16B, v13, v14); // cmeq v12.16B, v13.16B, v14.16B + __ cm(Assembler::EQ, v27, __ T4H, v28, v29); // cmeq v27.4H, v28.4H, v29.4H + __ cm(Assembler::EQ, v3, __ T8H, v4, v5); // cmeq v3.8H, v4.8H, v5.8H + __ cm(Assembler::EQ, v1, __ T2S, v2, v3); // cmeq v1.2S, v2.2S, v3.2S + __ cm(Assembler::EQ, v31, __ T4S, v0, v1); // cmeq v31.4S, v0.4S, v1.4S + __ cm(Assembler::EQ, v24, __ T2D, v25, v26); // cmeq v24.2D, v25.2D, v26.2D + __ cm(Assembler::HI, v19, __ T8B, v20, v21); // cmhi v19.8B, v20.8B, v21.8B + __ cm(Assembler::HI, v17, __ T16B, v18, v19); // cmhi v17.16B, v18.16B, v19.16B + __ cm(Assembler::HI, v9, __ T4H, v10, v11); // cmhi v9.4H, v10.4H, v11.4H + __ cm(Assembler::HI, v28, __ T8H, v29, v30); // cmhi v28.8H, v29.8H, v30.8H + __ cm(Assembler::HI, v27, __ T2S, v28, v29); // cmhi v27.2S, v28.2S, v29.2S + __ cm(Assembler::HI, v15, __ T4S, v16, v17); // cmhi v15.4S, v16.4S, v17.4S + __ cm(Assembler::HI, v7, __ T2D, v8, v9); // cmhi v7.2D, v8.2D, v9.2D + __ cm(Assembler::HS, v21, __ T8B, v22, v23); // cmhs v21.8B, v22.8B, v23.8B + __ cm(Assembler::HS, v23, __ T16B, v24, v25); // cmhs v23.16B, v24.16B, v25.16B + __ cm(Assembler::HS, v31, __ T4H, v0, v1); // cmhs v31.4H, v0.4H, v1.4H + __ cm(Assembler::HS, v25, __ T8H, v26, v27); // cmhs v25.8H, v26.8H, v27.8H + __ cm(Assembler::HS, v2, __ T2S, v3, v4); // cmhs v2.2S, v3.2S, v4.2S + __ cm(Assembler::HS, v31, __ T4S, v0, v1); // cmhs v31.4S, v0.4S, v1.4S + __ cm(Assembler::HS, v27, __ T2D, v28, v29); // cmhs v27.2D, v28.2D, v29.2D + __ fcm(Assembler::EQ, v18, __ T2S, v19, v20); // fcmeq v18.2S, v19.2S, v20.2S + __ fcm(Assembler::EQ, v10, __ T4S, v11, v12); // fcmeq v10.4S, v11.4S, v12.4S + __ fcm(Assembler::EQ, v23, __ T2D, v24, v25); // fcmeq v23.2D, v24.2D, v25.2D __ fcm(Assembler::GT, v19, __ T2S, v20, v21); // fcmgt v19.2S, v20.2S, v21.2S - __ fcm(Assembler::GT, v19, __ T4S, v20, v21); // fcmgt v19.4S, v20.4S, v21.4S - __ fcm(Assembler::GT, v22, __ T2D, v23, v24); // fcmgt v22.2D, v23.2D, v24.2D - __ fcm(Assembler::GE, v2, __ T2S, v3, v4); // fcmge v2.2S, v3.2S, v4.2S - __ fcm(Assembler::GE, v15, __ T4S, v16, v17); // fcmge v15.4S, v16.4S, v17.4S - __ fcm(Assembler::GE, v6, __ T2D, v7, v8); // fcmge v6.2D, v7.2D, v8.2D + __ fcm(Assembler::GT, v3, __ T4S, v4, v5); // fcmgt v3.4S, v4.4S, v5.4S + __ fcm(Assembler::GT, v18, __ T2D, v19, v20); // fcmgt v18.2D, v19.2D, v20.2D + __ fcm(Assembler::GE, v0, __ T2S, v1, v2); // fcmge v0.2S, v1.2S, v2.2S + __ fcm(Assembler::GE, v25, __ T4S, v26, v27); // fcmge v25.4S, v26.4S, v27.4S + __ fcm(Assembler::GE, v26, __ T2D, v27, v28); // fcmge v26.2D, v27.2D, v28.2D // SVEComparisonWithZero - __ sve_fcm(Assembler::EQ, p6, __ S, p3, z16, 0.0); // fcmeq p6.s, p3/z, z16.s, #0.0 - __ sve_fcm(Assembler::GT, p11, __ D, p4, z1, 0.0); // fcmgt p11.d, p4/z, z1.d, #0.0 - __ sve_fcm(Assembler::GE, p2, __ S, p4, z17, 0.0); // fcmge p2.s, p4/z, z17.s, #0.0 - __ sve_fcm(Assembler::LT, p11, __ S, p5, z13, 0.0); // fcmlt p11.s, p5/z, z13.s, #0.0 - __ sve_fcm(Assembler::LE, p14, __ S, p6, z27, 0.0); // fcmle p14.s, p6/z, z27.s, #0.0 - __ sve_fcm(Assembler::NE, p1, __ D, p6, z1, 0.0); // fcmne p1.d, p6/z, z1.d, #0.0 + __ sve_fcm(Assembler::EQ, p11, __ D, p3, z2, 0.0); // fcmeq p11.d, p3/z, z2.d, #0.0 + __ sve_fcm(Assembler::GT, p2, __ D, p7, z28, 0.0); // fcmgt p2.d, p7/z, z28.d, #0.0 + __ sve_fcm(Assembler::GE, p8, __ S, p2, z27, 0.0); // fcmge p8.s, p2/z, z27.s, #0.0 + __ sve_fcm(Assembler::LT, p14, __ S, p1, z18, 0.0); // fcmlt p14.s, p1/z, z18.s, #0.0 + __ sve_fcm(Assembler::LE, p3, __ S, p5, z15, 0.0); // fcmle p3.s, p5/z, z15.s, #0.0 + __ sve_fcm(Assembler::NE, p4, __ D, p5, z2, 0.0); // fcmne p4.d, p5/z, z2.d, #0.0 // SVEComparisonWithImm - __ sve_cmp(Assembler::EQ, p9, __ H, p7, z17, 11); // cmpeq p9.h, p7/z, z17.h, #11 - __ sve_cmp(Assembler::GT, p7, __ S, p5, z7, 15); // cmpgt p7.s, p5/z, z7.s, #15 - __ sve_cmp(Assembler::GE, p12, __ D, p6, z2, 2); // cmpge p12.d, p6/z, z2.d, #2 - __ sve_cmp(Assembler::LT, p5, __ S, p0, z23, 2); // cmplt p5.s, p0/z, z23.s, #2 - __ sve_cmp(Assembler::LE, p0, __ D, p5, z25, -14); // cmple p0.d, p5/z, z25.d, #-14 - __ sve_cmp(Assembler::NE, p9, __ B, p7, z12, 14); // cmpne p9.b, p7/z, z12.b, #14 - __ sve_cmp(Assembler::HS, p14, __ D, p1, z16, 37); // cmphs p14.d, p1/z, z16.d, #37 - __ sve_cmp(Assembler::HI, p14, __ B, p1, z18, 29); // cmphi p14.b, p1/z, z18.b, #29 - __ sve_cmp(Assembler::LS, p7, __ S, p2, z9, 10); // cmpls p7.s, p2/z, z9.s, #10 - __ sve_cmp(Assembler::LO, p14, __ D, p1, z21, 111); // cmplo p14.d, p1/z, z21.d, #111 + __ sve_cmp(Assembler::EQ, p15, __ D, p0, z5, 1); // cmpeq p15.d, p0/z, z5.d, #1 + __ sve_cmp(Assembler::GT, p7, __ D, p2, z4, 12); // cmpgt p7.d, p2/z, z4.d, #12 + __ sve_cmp(Assembler::GE, p11, __ D, p6, z27, 7); // cmpge p11.d, p6/z, z27.d, #7 + __ sve_cmp(Assembler::LT, p0, __ B, p4, z4, -16); // cmplt p0.b, p4/z, z4.b, #-16 + __ sve_cmp(Assembler::LE, p2, __ B, p2, z15, -9); // cmple p2.b, p2/z, z15.b, #-9 + __ sve_cmp(Assembler::NE, p2, __ D, p1, z10, 4); // cmpne p2.d, p1/z, z10.d, #4 + __ sve_cmp(Assembler::HS, p11, __ B, p2, z21, 34); // cmphs p11.b, p2/z, z21.b, #34 + __ sve_cmp(Assembler::HI, p8, __ B, p4, z31, 8); // cmphi p8.b, p4/z, z31.b, #8 + __ sve_cmp(Assembler::LS, p6, __ D, p0, z30, 109); // cmpls p6.d, p0/z, z30.d, #109 + __ sve_cmp(Assembler::LO, p11, __ H, p3, z29, 114); // cmplo p11.h, p3/z, z29.h, #114 // SpecialCases __ ccmn(zr, zr, 3u, Assembler::LE); // ccmn xzr, xzr, #3, LE @@ -1136,239 +1152,239 @@ __ fmovd(v0, -1.0625); // fmov d0, #-1.0625 // LSEOp - __ swp(Assembler::xword, r0, r17, r15); // swp x0, x17, [x15] - __ ldadd(Assembler::xword, r4, r26, r8); // ldadd x4, x26, [x8] - __ ldbic(Assembler::xword, r28, r22, r27); // ldclr x28, x22, [x27] - __ ldeor(Assembler::xword, r27, r25, r23); // ldeor x27, x25, [x23] - __ ldorr(Assembler::xword, r0, r4, r6); // ldset x0, x4, [x6] - __ ldsmin(Assembler::xword, r16, r0, r4); // ldsmin x16, x0, [x4] - __ ldsmax(Assembler::xword, r15, r1, r10); // ldsmax x15, x1, [x10] - __ ldumin(Assembler::xword, r7, r5, r10); // ldumin x7, x5, [x10] - __ ldumax(Assembler::xword, r28, r7, r20); // ldumax x28, x7, [x20] + __ swp(Assembler::xword, r17, r24, r5); // swp x17, x24, [x5] + __ ldadd(Assembler::xword, r2, r14, r10); // ldadd x2, x14, [x10] + __ ldbic(Assembler::xword, r16, r11, r27); // ldclr x16, x11, [x27] + __ ldeor(Assembler::xword, r23, r12, r4); // ldeor x23, x12, [x4] + __ ldorr(Assembler::xword, r22, r17, r4); // ldset x22, x17, [x4] + __ ldsmin(Assembler::xword, r1, r19, r16); // ldsmin x1, x19, [x16] + __ ldsmax(Assembler::xword, r16, r13, r14); // ldsmax x16, x13, [x14] + __ ldumin(Assembler::xword, r12, r2, r17); // ldumin x12, x2, [x17] + __ ldumax(Assembler::xword, r3, r21, r23); // ldumax x3, x21, [x23] // LSEOp - __ swpa(Assembler::xword, r23, r21, r6); // swpa x23, x21, [x6] - __ ldadda(Assembler::xword, r11, r8, r17); // ldadda x11, x8, [x17] - __ ldbica(Assembler::xword, zr, r6, r17); // ldclra xzr, x6, [x17] - __ ldeora(Assembler::xword, r2, r12, r30); // ldeora x2, x12, [x30] - __ ldorra(Assembler::xword, r29, r3, r27); // ldseta x29, x3, [x27] - __ ldsmina(Assembler::xword, r22, r29, r14); // ldsmina x22, x29, [x14] - __ ldsmaxa(Assembler::xword, r13, r28, r17); // ldsmaxa x13, x28, [x17] - __ ldumina(Assembler::xword, r24, r5, r2); // ldumina x24, x5, [x2] - __ ldumaxa(Assembler::xword, r14, r10, r16); // ldumaxa x14, x10, [x16] + __ swpa(Assembler::xword, r5, r6, r7); // swpa x5, x6, [x7] + __ ldadda(Assembler::xword, r19, r13, r28); // ldadda x19, x13, [x28] + __ ldbica(Assembler::xword, r17, r16, r6); // ldclra x17, x16, [x6] + __ ldeora(Assembler::xword, r2, r29, r3); // ldeora x2, x29, [x3] + __ ldorra(Assembler::xword, r4, r6, r15); // ldseta x4, x6, [x15] + __ ldsmina(Assembler::xword, r20, r13, r12); // ldsmina x20, x13, [x12] + __ ldsmaxa(Assembler::xword, r20, r8, r25); // ldsmaxa x20, x8, [x25] + __ ldumina(Assembler::xword, r20, r19, r0); // ldumina x20, x19, [x0] + __ ldumaxa(Assembler::xword, r11, r24, r6); // ldumaxa x11, x24, [x6] // LSEOp - __ swpal(Assembler::xword, r11, r27, r23); // swpal x11, x27, [x23] - __ ldaddal(Assembler::xword, r12, r4, r22); // ldaddal x12, x4, [x22] - __ ldbical(Assembler::xword, r17, r4, r1); // ldclral x17, x4, [x1] - __ ldeoral(Assembler::xword, r19, r16, r15); // ldeoral x19, x16, [x15] - __ ldorral(Assembler::xword, r13, r14, r12); // ldsetal x13, x14, [x12] - __ ldsminal(Assembler::xword, r2, r17, r3); // ldsminal x2, x17, [x3] - __ ldsmaxal(Assembler::xword, r21, r23, r5); // ldsmaxal x21, x23, [x5] - __ lduminal(Assembler::xword, r6, r7, r19); // lduminal x6, x7, [x19] - __ ldumaxal(Assembler::xword, r13, r28, r17); // ldumaxal x13, x28, [x17] + __ swpal(Assembler::xword, r20, zr, r14); // swpal x20, xzr, [x14] + __ ldaddal(Assembler::xword, r16, r6, r0); // ldaddal x16, x6, [x0] + __ ldbical(Assembler::xword, r7, r15, r19); // ldclral x7, x15, [x19] + __ ldeoral(Assembler::xword, r26, r9, r10); // ldeoral x26, x9, [x10] + __ ldorral(Assembler::xword, r23, r21, r22); // ldsetal x23, x21, [x22] + __ ldsminal(Assembler::xword, r28, r2, r3); // ldsminal x28, x2, [x3] + __ ldsmaxal(Assembler::xword, r15, r19, r20); // ldsmaxal x15, x19, [x20] + __ lduminal(Assembler::xword, r7, r4, r29); // lduminal x7, x4, [x29] + __ ldumaxal(Assembler::xword, r7, r0, r9); // ldumaxal x7, x0, [x9] // LSEOp - __ swpl(Assembler::xword, r16, r6, r2); // swpl x16, x6, [x2] - __ ldaddl(Assembler::xword, r29, r3, r4); // ldaddl x29, x3, [x4] - __ ldbicl(Assembler::xword, r6, r16, r20); // ldclrl x6, x16, [x20] - __ ldeorl(Assembler::xword, r13, r12, r20); // ldeorl x13, x12, [x20] - __ ldorrl(Assembler::xword, r8, r25, r20); // ldsetl x8, x25, [x20] - __ ldsminl(Assembler::xword, r19, r0, r11); // ldsminl x19, x0, [x11] - __ ldsmaxl(Assembler::xword, r24, r6, r20); // ldsmaxl x24, x6, [x20] - __ lduminl(Assembler::xword, zr, r14, r16); // lduminl xzr, x14, [x16] - __ ldumaxl(Assembler::xword, r6, r0, r7); // ldumaxl x6, x0, [x7] + __ swpl(Assembler::xword, r16, r20, r23); // swpl x16, x20, [x23] + __ ldaddl(Assembler::xword, r4, r16, r10); // ldaddl x4, x16, [x10] + __ ldbicl(Assembler::xword, r23, r11, r25); // ldclrl x23, x11, [x25] + __ ldeorl(Assembler::xword, r6, zr, r16); // ldeorl x6, xzr, [x16] + __ ldorrl(Assembler::xword, r13, r23, r12); // ldsetl x13, x23, [x12] + __ ldsminl(Assembler::xword, r1, r14, r9); // ldsminl x1, x14, [x9] + __ ldsmaxl(Assembler::xword, r21, r16, r26); // ldsmaxl x21, x16, [x26] + __ lduminl(Assembler::xword, r15, r4, r4); // lduminl x15, x4, [x4] + __ ldumaxl(Assembler::xword, r16, r8, r6); // ldumaxl x16, x8, [x6] // LSEOp - __ swp(Assembler::word, r15, r19, r26); // swp w15, w19, [x26] - __ ldadd(Assembler::word, r9, r10, r23); // ldadd w9, w10, [x23] - __ ldbic(Assembler::word, r21, r22, r28); // ldclr w21, w22, [x28] - __ ldeor(Assembler::word, r2, r3, r15); // ldeor w2, w3, [x15] - __ ldorr(Assembler::word, r19, r20, r7); // ldset w19, w20, [x7] - __ ldsmin(Assembler::word, r4, r29, r7); // ldsmin w4, w29, [x7] - __ ldsmax(Assembler::word, r0, r9, r16); // ldsmax w0, w9, [x16] - __ ldumin(Assembler::word, r20, r23, r4); // ldumin w20, w23, [x4] - __ ldumax(Assembler::word, r16, r10, r23); // ldumax w16, w10, [x23] + __ swp(Assembler::word, r30, r4, r29); // swp w30, w4, [x29] + __ ldadd(Assembler::word, r17, r29, r26); // ldadd w17, w29, [x26] + __ ldbic(Assembler::word, r9, r15, r2); // ldclr w9, w15, [x2] + __ ldeor(Assembler::word, r11, r29, r3); // ldeor w11, w29, [x3] + __ ldorr(Assembler::word, r7, r1, r27); // ldset w7, w1, [x27] + __ ldsmin(Assembler::word, r21, r16, r14); // ldsmin w21, w16, [x14] + __ ldsmax(Assembler::word, r8, r16, r22); // ldsmax w8, w16, [x22] + __ ldumin(Assembler::word, r25, r5, r20); // ldumin w25, w5, [x20] + __ ldumax(Assembler::word, r21, r16, r23); // ldumax w21, w16, [x23] // LSEOp - __ swpa(Assembler::word, r11, r25, r6); // swpa w11, w25, [x6] - __ ldadda(Assembler::word, zr, r16, r13); // ldadda wzr, w16, [x13] - __ ldbica(Assembler::word, r23, r12, r1); // ldclra w23, w12, [x1] - __ ldeora(Assembler::word, r14, r9, r21); // ldeora w14, w9, [x21] - __ ldorra(Assembler::word, r16, r26, r15); // ldseta w16, w26, [x15] - __ ldsmina(Assembler::word, r4, r4, r15); // ldsmina w4, w4, [x15] - __ ldsmaxa(Assembler::word, r8, r6, r30); // ldsmaxa w8, w6, [x30] - __ ldumina(Assembler::word, r4, r29, r17); // ldumina w4, w29, [x17] - __ ldumaxa(Assembler::word, r29, r26, r9); // ldumaxa w29, w26, [x9] + __ swpa(Assembler::word, r16, r30, r20); // swpa w16, w30, [x20] + __ ldadda(Assembler::word, r20, r0, r4); // ldadda w20, w0, [x4] + __ ldbica(Assembler::word, r19, r24, r4); // ldclra w19, w24, [x4] + __ ldeora(Assembler::word, r20, r4, r24); // ldeora w20, w4, [x24] + __ ldorra(Assembler::word, r26, r19, r2); // ldseta w26, w19, [x2] + __ ldsmina(Assembler::word, r8, r8, r14); // ldsmina w8, w8, [x14] + __ ldsmaxa(Assembler::word, r24, r16, sp); // ldsmaxa w24, w16, [sp] + __ ldumina(Assembler::word, r22, r4, sp); // ldumina w22, w4, [sp] + __ ldumaxa(Assembler::word, r1, r10, r20); // ldumaxa w1, w10, [x20] // LSEOp - __ swpal(Assembler::word, r15, r2, r11); // swpal w15, w2, [x11] - __ ldaddal(Assembler::word, r29, r3, r7); // ldaddal w29, w3, [x7] - __ ldbical(Assembler::word, r1, r27, r21); // ldclral w1, w27, [x21] - __ ldeoral(Assembler::word, r16, r14, r8); // ldeoral w16, w14, [x8] - __ ldorral(Assembler::word, r16, r22, r25); // ldsetal w16, w22, [x25] - __ ldsminal(Assembler::word, r5, r20, r21); // ldsminal w5, w20, [x21] - __ ldsmaxal(Assembler::word, r16, r23, r16); // ldsmaxal w16, w23, [x16] - __ lduminal(Assembler::word, r30, r20, r20); // lduminal w30, w20, [x20] - __ ldumaxal(Assembler::word, r0, r4, r19); // ldumaxal w0, w4, [x19] + __ swpal(Assembler::word, r12, r0, r9); // swpal w12, w0, [x9] + __ ldaddal(Assembler::word, r7, r24, r15); // ldaddal w7, w24, [x15] + __ ldbical(Assembler::word, r4, r27, r6); // ldclral w4, w27, [x6] + __ ldeoral(Assembler::word, r10, r27, r24); // ldeoral w10, w27, [x24] + __ ldorral(Assembler::word, r13, r16, sp); // ldsetal w13, w16, [sp] + __ ldsminal(Assembler::word, r22, r22, r20); // ldsminal w22, w22, [x20] + __ ldsmaxal(Assembler::word, zr, r29, r9); // ldsmaxal wzr, w29, [x9] + __ lduminal(Assembler::word, r14, r20, r7); // lduminal w14, w20, [x7] + __ ldumaxal(Assembler::word, r20, r28, r9); // ldumaxal w20, w28, [x9] // LSEOp - __ swpl(Assembler::word, r24, r4, r20); // swpl w24, w4, [x20] - __ ldaddl(Assembler::word, r4, r24, r26); // ldaddl w4, w24, [x26] - __ ldbicl(Assembler::word, r19, r2, r8); // ldclrl w19, w2, [x8] - __ ldeorl(Assembler::word, r8, r14, r24); // ldeorl w8, w14, [x24] - __ ldorrl(Assembler::word, r16, zr, r22); // ldsetl w16, wzr, [x22] - __ ldsminl(Assembler::word, r4, zr, r1); // ldsminl w4, wzr, [x1] - __ ldsmaxl(Assembler::word, r10, r20, r12); // ldsmaxl w10, w20, [x12] - __ lduminl(Assembler::word, r0, r9, r7); // lduminl w0, w9, [x7] - __ ldumaxl(Assembler::word, r24, r16, r4); // ldumaxl w24, w16, [x4] + __ swpl(Assembler::word, r11, r14, r12); // swpl w11, w14, [x12] + __ ldaddl(Assembler::word, r20, r1, r24); // ldaddl w20, w1, [x24] + __ ldbicl(Assembler::word, r9, r19, r13); // ldclrl w9, w19, [x13] + __ ldeorl(Assembler::word, r19, r16, r16); // ldeorl w19, w16, [x16] + __ ldorrl(Assembler::word, r5, r0, r3); // ldsetl w5, w0, [x3] + __ ldsminl(Assembler::word, r12, r8, r15); // ldsminl w12, w8, [x15] + __ ldsmaxl(Assembler::word, r15, r16, r4); // ldsmaxl w15, w16, [x4] + __ lduminl(Assembler::word, r15, r30, r5); // lduminl w15, w30, [x5] + __ ldumaxl(Assembler::word, r0, r10, r22); // ldumaxl w0, w10, [x22] // SHA3SIMDOp - __ bcax(v27, __ T16B, v6, v10, v27); // bcax v27.16B, v6.16B, v10.16B, v27.16B - __ eor3(v24, __ T16B, v13, v16, v31); // eor3 v24.16B, v13.16B, v16.16B, v31.16B - __ rax1(v22, __ T2D, v22, v20); // rax1 v22.2D, v22.2D, v20.2D - __ xar(v31, __ T2D, v29, v9, 28); // xar v31.2D, v29.2D, v9.2D, #28 + __ bcax(v27, __ T16B, v3, v0, v9); // bcax v27.16B, v3.16B, v0.16B, v9.16B + __ eor3(v19, __ T16B, v29, v10, v24); // eor3 v19.16B, v29.16B, v10.16B, v24.16B + __ rax1(v4, __ T2D, v20, v7); // rax1 v4.2D, v20.2D, v7.2D + __ xar(v24, __ T2D, v29, v14, 43); // xar v24.2D, v29.2D, v14.2D, #43 // SHA512SIMDOp - __ sha512h(v20, __ T2D, v7, v20); // sha512h q20, q7, v20.2D - __ sha512h2(v28, __ T2D, v9, v11); // sha512h2 q28, q9, v11.2D - __ sha512su0(v14, __ T2D, v12); // sha512su0 v14.2D, v12.2D - __ sha512su1(v20, __ T2D, v1, v24); // sha512su1 v20.2D, v1.2D, v24.2D + __ sha512h(v11, __ T2D, v27, v13); // sha512h q11, q27, v13.2D + __ sha512h2(v18, __ T2D, v31, v17); // sha512h2 q18, q31, v17.2D + __ sha512su0(v14, __ T2D, v3); // sha512su0 v14.2D, v3.2D + __ sha512su1(v30, __ T2D, v16, v22); // sha512su1 v30.2D, v16.2D, v22.2D // SVEBinaryImmOp - __ sve_add(z9, __ S, 108u); // add z9.s, z9.s, #0x6c - __ sve_sub(z19, __ S, 132u); // sub z19.s, z19.s, #0x84 - __ sve_and(z5, __ B, 124u); // and z5.b, z5.b, #0x7c - __ sve_eor(z8, __ H, 32768u); // eor z8.h, z8.h, #0x8000 - __ sve_orr(z4, __ H, 508u); // orr z4.h, z4.h, #0x1fc + __ sve_add(z20, __ B, 163u); // add z20.b, z20.b, #0xa3 + __ sve_sub(z3, __ B, 215u); // sub z3.b, z3.b, #0xd7 + __ sve_and(z19, __ H, 33279u); // and z19.h, z19.h, #0x81ff + __ sve_eor(z21, __ B, 12u); // eor z21.b, z21.b, #0xc + __ sve_orr(z24, __ H, 8064u); // orr z24.h, z24.h, #0x1f80 // SVEBinaryImmOp - __ sve_add(z0, __ H, 181u); // add z0.h, z0.h, #0xb5 - __ sve_sub(z27, __ B, 7u); // sub z27.b, z27.b, #0x7 - __ sve_and(z9, __ S, 130023424u); // and z9.s, z9.s, #0x7c00000 - __ sve_eor(z24, __ B, 62u); // eor z24.b, z24.b, #0x3e - __ sve_orr(z24, __ D, 18428729675200069887u); // orr z24.d, z24.d, #0xffc00000000000ff + __ sve_add(z21, __ H, 139u); // add z21.h, z21.h, #0x8b + __ sve_sub(z30, __ H, 26u); // sub z30.h, z30.h, #0x1a + __ sve_and(z3, __ S, 122880u); // and z3.s, z3.s, #0x1e000 + __ sve_eor(z24, __ D, 18158513714670600195u); // eor z24.d, z24.d, #0xfc000003fc000003 + __ sve_orr(z23, __ B, 191u); // orr z23.b, z23.b, #0xbf // SVEBinaryImmOp - __ sve_add(z11, __ D, 104u); // add z11.d, z11.d, #0x68 - __ sve_sub(z18, __ D, 142u); // sub z18.d, z18.d, #0x8e - __ sve_and(z14, __ B, 131u); // and z14.b, z14.b, #0x83 - __ sve_eor(z22, __ S, 4042322160u); // eor z22.s, z22.s, #0xf0f0f0f0 - __ sve_orr(z3, __ B, 225u); // orr z3.b, z3.b, #0xe1 + __ sve_add(z14, __ B, 66u); // add z14.b, z14.b, #0x42 + __ sve_sub(z26, __ B, 180u); // sub z26.b, z26.b, #0xb4 + __ sve_and(z18, __ S, 253952u); // and z18.s, z18.s, #0x3e000 + __ sve_eor(z9, __ S, 16744448u); // eor z9.s, z9.s, #0xff8000 + __ sve_orr(z12, __ H, 33279u); // orr z12.h, z12.h, #0x81ff // SVEBinaryImmOp - __ sve_add(z9, __ S, 142u); // add z9.s, z9.s, #0x8e - __ sve_sub(z21, __ B, 36u); // sub z21.b, z21.b, #0x24 - __ sve_and(z2, __ D, 8796093020160u); // and z2.d, z2.d, #0x7fffffff800 - __ sve_eor(z11, __ S, 3221229567u); // eor z11.s, z11.s, #0xc0000fff - __ sve_orr(z30, __ H, 126u); // orr z30.h, z30.h, #0x7e + __ sve_add(z11, __ H, 206u); // add z11.h, z11.h, #0xce + __ sve_sub(z18, __ D, 154u); // sub z18.d, z18.d, #0x9a + __ sve_and(z9, __ S, 4294459391u); // and z9.s, z9.s, #0xfff83fff + __ sve_eor(z23, __ D, 562675075514368u); // eor z23.d, z23.d, #0x1ffc000000000 + __ sve_orr(z8, __ B, 243u); // orr z8.b, z8.b, #0xf3 // SVEBinaryImmOp - __ sve_add(z23, __ H, 29u); // add z23.h, z23.h, #0x1d - __ sve_sub(z24, __ D, 26u); // sub z24.d, z24.d, #0x1a - __ sve_and(z19, __ S, 4294049777u); // and z19.s, z19.s, #0xfff1fff1 - __ sve_eor(z21, __ H, 1008u); // eor z21.h, z21.h, #0x3f0 - __ sve_orr(z26, __ B, 131u); // orr z26.b, z26.b, #0x83 + __ sve_add(z10, __ B, 121u); // add z10.b, z10.b, #0x79 + __ sve_sub(z25, __ S, 172u); // sub z25.s, z25.s, #0xac + __ sve_and(z0, __ B, 239u); // and z0.b, z0.b, #0xef + __ sve_eor(z5, __ D, 17870287719452639231u); // eor z5.d, z5.d, #0xf80003ffffffffff + __ sve_orr(z17, __ B, 128u); // orr z17.b, z17.b, #0x80 // SVEBinaryImmOp - __ sve_add(z17, __ B, 31u); // add z17.b, z17.b, #0x1f - __ sve_sub(z9, __ S, 97u); // sub z9.s, z9.s, #0x61 - __ sve_and(z8, __ H, 49155u); // and z8.h, z8.h, #0xc003 - __ sve_eor(z17, __ H, 57855u); // eor z17.h, z17.h, #0xe1ff - __ sve_orr(z18, __ D, 2251799811588096u); // orr z18.d, z18.d, #0x7ffffffe00000 + __ sve_add(z30, __ H, 3u); // add z30.h, z30.h, #0x3 + __ sve_sub(z18, __ B, 253u); // sub z18.b, z18.b, #0xfd + __ sve_and(z21, __ S, 4294965263u); // and z21.s, z21.s, #0xfffff80f + __ sve_eor(z12, __ H, 1u); // eor z12.h, z12.h, #0x1 + __ sve_orr(z15, __ S, 1u); // orr z15.s, z15.s, #0x1 // SVEVectorOp - __ sve_add(z16, __ S, z15, z27); // add z16.s, z15.s, z27.s - __ sve_sub(z28, __ H, z22, z8); // sub z28.h, z22.h, z8.h - __ sve_fadd(z5, __ S, z28, z28); // fadd z5.s, z28.s, z28.s - __ sve_fmul(z0, __ D, z15, z25); // fmul z0.d, z15.d, z25.d - __ sve_fsub(z21, __ D, z0, z3); // fsub z21.d, z0.d, z3.d - __ sve_sqadd(z26, __ D, z5, z26); // sqadd z26.d, z5.d, z26.d - __ sve_sqsub(z19, __ H, z17, z1); // sqsub z19.h, z17.h, z1.h - __ sve_uqadd(z14, __ B, z30, z14); // uqadd z14.b, z30.b, z14.b - __ sve_uqsub(z18, __ S, z2, z31); // uqsub z18.s, z2.s, z31.s - __ sve_abs(z23, __ H, p5, z30); // abs z23.h, p5/m, z30.h - __ sve_add(z8, __ H, p0, z0); // add z8.h, p0/m, z8.h, z0.h - __ sve_and(z23, __ S, p5, z0); // and z23.s, p5/m, z23.s, z0.s - __ sve_asr(z26, __ H, p6, z24); // asr z26.h, p6/m, z26.h, z24.h - __ sve_bic(z22, __ B, p5, z2); // bic z22.b, p5/m, z22.b, z2.b - __ sve_clz(z11, __ S, p5, z12); // clz z11.s, p5/m, z12.s - __ sve_cnt(z24, __ D, p6, z9); // cnt z24.d, p6/m, z9.d - __ sve_eor(z17, __ S, p5, z20); // eor z17.s, p5/m, z17.s, z20.s - __ sve_lsl(z4, __ D, p5, z13); // lsl z4.d, p5/m, z4.d, z13.d - __ sve_lsr(z22, __ D, p7, z31); // lsr z22.d, p7/m, z22.d, z31.d - __ sve_mul(z18, __ H, p4, z15); // mul z18.h, p4/m, z18.h, z15.h - __ sve_neg(z13, __ B, p7, z20); // neg z13.b, p7/m, z20.b - __ sve_not(z1, __ B, p3, z14); // not z1.b, p3/m, z14.b - __ sve_orr(z7, __ S, p2, z12); // orr z7.s, p2/m, z7.s, z12.s - __ sve_rbit(z4, __ B, p6, z15); // rbit z4.b, p6/m, z15.b - __ sve_revb(z3, __ S, p7, z1); // revb z3.s, p7/m, z1.s - __ sve_smax(z5, __ D, p5, z31); // smax z5.d, p5/m, z5.d, z31.d - __ sve_smin(z13, __ H, p3, z9); // smin z13.h, p3/m, z13.h, z9.h - __ sve_umax(z30, __ D, p0, z15); // umax z30.d, p0/m, z30.d, z15.d - __ sve_umin(z3, __ H, p0, z26); // umin z3.h, p0/m, z3.h, z26.h - __ sve_sub(z25, __ D, p2, z1); // sub z25.d, p2/m, z25.d, z1.d - __ sve_fabs(z10, __ D, p3, z1); // fabs z10.d, p3/m, z1.d - __ sve_fadd(z26, __ D, p1, z29); // fadd z26.d, p1/m, z26.d, z29.d - __ sve_fdiv(z17, __ S, p1, z28); // fdiv z17.s, p1/m, z17.s, z28.s - __ sve_fmax(z1, __ S, p7, z11); // fmax z1.s, p7/m, z1.s, z11.s - __ sve_fmin(z1, __ D, p0, z1); // fmin z1.d, p0/m, z1.d, z1.d - __ sve_fmul(z27, __ S, p3, z2); // fmul z27.s, p3/m, z27.s, z2.s - __ sve_fneg(z30, __ S, p4, z25); // fneg z30.s, p4/m, z25.s - __ sve_frintm(z2, __ D, p6, z3); // frintm z2.d, p6/m, z3.d - __ sve_frintn(z29, __ D, p3, z3); // frintn z29.d, p3/m, z3.d - __ sve_frintp(z14, __ D, p4, z28); // frintp z14.d, p4/m, z28.d - __ sve_fsqrt(z4, __ D, p2, z27); // fsqrt z4.d, p2/m, z27.d - __ sve_fsub(z2, __ D, p4, z1); // fsub z2.d, p4/m, z2.d, z1.d - __ sve_fmad(z7, __ D, p5, z31, z28); // fmad z7.d, p5/m, z31.d, z28.d - __ sve_fmla(z10, __ S, p5, z17, z29); // fmla z10.s, p5/m, z17.s, z29.s - __ sve_fmls(z22, __ S, p1, z12, z24); // fmls z22.s, p1/m, z12.s, z24.s - __ sve_fmsb(z9, __ S, p2, z11, z0); // fmsb z9.s, p2/m, z11.s, z0.s - __ sve_fnmad(z23, __ S, p5, z20, z4); // fnmad z23.s, p5/m, z20.s, z4.s - __ sve_fnmsb(z15, __ D, p3, z4, z30); // fnmsb z15.d, p3/m, z4.d, z30.d - __ sve_fnmla(z27, __ S, p1, z21, z26); // fnmla z27.s, p1/m, z21.s, z26.s - __ sve_fnmls(z31, __ S, p0, z25, z4); // fnmls z31.s, p0/m, z25.s, z4.s - __ sve_mla(z6, __ D, p0, z21, z7); // mla z6.d, p0/m, z21.d, z7.d - __ sve_mls(z24, __ S, p7, z24, z31); // mls z24.s, p7/m, z24.s, z31.s - __ sve_and(z1, z10, z12); // and z1.d, z10.d, z12.d - __ sve_eor(z13, z8, z25); // eor z13.d, z8.d, z25.d - __ sve_orr(z1, z31, z23); // orr z1.d, z31.d, z23.d - __ sve_bic(z20, z0, z21); // bic z20.d, z0.d, z21.d - __ sve_uzp1(z31, __ S, z29, z27); // uzp1 z31.s, z29.s, z27.s - __ sve_uzp2(z8, __ S, z29, z26); // uzp2 z8.s, z29.s, z26.s - __ sve_fabd(z5, __ D, p1, z18); // fabd z5.d, p1/m, z5.d, z18.d - __ sve_bext(z13, __ H, z26, z21); // bext z13.h, z26.h, z21.h - __ sve_bdep(z0, __ D, z19, z10); // bdep z0.d, z19.d, z10.d - __ sve_eor3(z7, z17, z6); // eor3 z7.d, z7.d, z17.d, z6.d - __ sve_sqadd(z20, __ H, p6, z28); // sqadd z20.h, p6/m, z20.h, z28.h - __ sve_sqsub(z17, __ H, p3, z19); // sqsub z17.h, p3/m, z17.h, z19.h - __ sve_uqadd(z26, __ B, p2, z24); // uqadd z26.b, p2/m, z26.b, z24.b - __ sve_uqsub(z11, __ S, p3, z28); // uqsub z11.s, p3/m, z11.s, z28.s + __ sve_add(z19, __ D, z26, z27); // add z19.d, z26.d, z27.d + __ sve_sub(z13, __ B, z22, z22); // sub z13.b, z22.b, z22.b + __ sve_fadd(z1, __ S, z11, z20); // fadd z1.s, z11.s, z20.s + __ sve_fmul(z20, __ S, z24, z24); // fmul z20.s, z24.s, z24.s + __ sve_fsub(z31, __ D, z17, z20); // fsub z31.d, z17.d, z20.d + __ sve_sqadd(z21, __ H, z4, z21); // sqadd z21.h, z4.h, z21.h + __ sve_sqsub(z30, __ D, z22, z31); // sqsub z30.d, z22.d, z31.d + __ sve_uqadd(z26, __ H, z18, z19); // uqadd z26.h, z18.h, z19.h + __ sve_uqsub(z11, __ S, z13, z29); // uqsub z11.s, z13.s, z29.s + __ sve_abs(z5, __ H, p0, z14); // abs z5.h, p0/m, z14.h + __ sve_add(z2, __ H, p1, z10); // add z2.h, p1/m, z2.h, z10.h + __ sve_and(z19, __ H, p1, z26); // and z19.h, p1/m, z19.h, z26.h + __ sve_asr(z2, __ B, p0, z30); // asr z2.b, p0/m, z2.b, z30.b + __ sve_bic(z20, __ D, p1, z20); // bic z20.d, p1/m, z20.d, z20.d + __ sve_clz(z29, __ H, p3, z13); // clz z29.h, p3/m, z13.h + __ sve_cnt(z14, __ H, p7, z1); // cnt z14.h, p7/m, z1.h + __ sve_eor(z28, __ D, p0, z3); // eor z28.d, p0/m, z28.d, z3.d + __ sve_lsl(z9, __ B, p6, z9); // lsl z9.b, p6/m, z9.b, z9.b + __ sve_lsr(z26, __ B, p2, z14); // lsr z26.b, p2/m, z26.b, z14.b + __ sve_mul(z20, __ D, p6, z7); // mul z20.d, p6/m, z20.d, z7.d + __ sve_neg(z20, __ D, p4, z6); // neg z20.d, p4/m, z6.d + __ sve_not(z13, __ H, p0, z29); // not z13.h, p0/m, z29.h + __ sve_orr(z9, __ B, p0, z1); // orr z9.b, p0/m, z9.b, z1.b + __ sve_rbit(z27, __ B, p6, z15); // rbit z27.b, p6/m, z15.b + __ sve_revb(z4, __ D, p7, z17); // revb z4.d, p7/m, z17.d + __ sve_smax(z2, __ B, p0, z24); // smax z2.b, p0/m, z2.b, z24.b + __ sve_smin(z26, __ B, p7, z13); // smin z26.b, p7/m, z26.b, z13.b + __ sve_umax(z22, __ D, p3, z16); // umax z22.d, p3/m, z22.d, z16.d + __ sve_umin(z17, __ D, p1, z11); // umin z17.d, p1/m, z17.d, z11.d + __ sve_sub(z16, __ B, p0, z16); // sub z16.b, p0/m, z16.b, z16.b + __ sve_fabs(z28, __ D, p1, z23); // fabs z28.d, p1/m, z23.d + __ sve_fadd(z28, __ D, p4, z10); // fadd z28.d, p4/m, z28.d, z10.d + __ sve_fdiv(z17, __ D, p7, z7); // fdiv z17.d, p7/m, z17.d, z7.d + __ sve_fmax(z4, __ S, p3, z24); // fmax z4.s, p3/m, z4.s, z24.s + __ sve_fmin(z9, __ S, p2, z11); // fmin z9.s, p2/m, z9.s, z11.s + __ sve_fmul(z4, __ D, p5, z22); // fmul z4.d, p5/m, z4.d, z22.d + __ sve_fneg(z4, __ S, p0, z15); // fneg z4.s, p0/m, z15.s + __ sve_frintm(z4, __ D, p7, z26); // frintm z4.d, p7/m, z26.d + __ sve_frintn(z5, __ S, p5, z26); // frintn z5.s, p5/m, z26.s + __ sve_frintp(z31, __ S, p0, z25); // frintp z31.s, p0/m, z25.s + __ sve_fsqrt(z8, __ D, p1, z3); // fsqrt z8.d, p1/m, z3.d + __ sve_fsub(z7, __ D, p6, z24); // fsub z7.d, p6/m, z7.d, z24.d + __ sve_fmad(z24, __ S, p7, z17, z1); // fmad z24.s, p7/m, z17.s, z1.s + __ sve_fmla(z12, __ D, p7, z13, z8); // fmla z12.d, p7/m, z13.d, z8.d + __ sve_fmls(z29, __ D, p0, z31, z23); // fmls z29.d, p0/m, z31.d, z23.d + __ sve_fmsb(z20, __ D, p0, z21, z7); // fmsb z20.d, p0/m, z21.d, z7.d + __ sve_fnmad(z29, __ D, p6, z22, z8); // fnmad z29.d, p6/m, z22.d, z8.d + __ sve_fnmsb(z26, __ D, p5, z5, z6); // fnmsb z26.d, p5/m, z5.d, z6.d + __ sve_fnmla(z18, __ S, p3, z26, z21); // fnmla z18.s, p3/m, z26.s, z21.s + __ sve_fnmls(z0, __ S, p4, z10, z28); // fnmls z0.s, p4/m, z10.s, z28.s + __ sve_mla(z17, __ D, p1, z30, z20); // mla z17.d, p1/m, z30.d, z20.d + __ sve_mls(z28, __ S, p3, z17, z14); // mls z28.s, p3/m, z17.s, z14.s + __ sve_and(z10, z26, z11); // and z10.d, z26.d, z11.d + __ sve_eor(z0, z11, z15); // eor z0.d, z11.d, z15.d + __ sve_orr(z23, z23, z20); // orr z23.d, z23.d, z20.d + __ sve_bic(z23, z20, z29); // bic z23.d, z20.d, z29.d + __ sve_uzp1(z0, __ S, z27, z6); // uzp1 z0.s, z27.s, z6.s + __ sve_uzp2(z13, __ H, z12, z4); // uzp2 z13.h, z12.h, z4.h + __ sve_fabd(z31, __ D, p6, z23); // fabd z31.d, p6/m, z31.d, z23.d + __ sve_bext(z6, __ D, z2, z29); // bext z6.d, z2.d, z29.d + __ sve_bdep(z0, __ B, z29, z23); // bdep z0.b, z29.b, z23.b + __ sve_eor3(z4, z5, z8); // eor3 z4.d, z4.d, z5.d, z8.d + __ sve_sqadd(z13, __ H, p4, z13); // sqadd z13.h, p4/m, z13.h, z13.h + __ sve_sqsub(z8, __ H, p2, z8); // sqsub z8.h, p2/m, z8.h, z8.h + __ sve_uqadd(z19, __ S, p0, z29); // uqadd z19.s, p0/m, z19.s, z29.s + __ sve_uqsub(z16, __ D, p3, z23); // uqsub z16.d, p3/m, z16.d, z23.d // SVEReductionOp - __ sve_andv(v23, __ S, p5, z28); // andv s23, p5, z28.s - __ sve_orv(v20, __ B, p7, z24); // orv b20, p7, z24.b - __ sve_eorv(v27, __ H, p1, z23); // eorv h27, p1, z23.h - __ sve_smaxv(v12, __ D, p1, z13); // smaxv d12, p1, z13.d - __ sve_sminv(v26, __ B, p5, z20); // sminv b26, p5, z20.b - __ sve_fminv(v2, __ S, p7, z29); // fminv s2, p7, z29.s - __ sve_fmaxv(v29, __ S, p5, z3); // fmaxv s29, p5, z3.s - __ sve_fadda(v5, __ S, p2, z28); // fadda s5, p2, s5, z28.s - __ sve_uaddv(v17, __ H, p3, z14); // uaddv d17, p3, z14.h + __ sve_andv(v23, __ B, p7, z13); // andv b23, p7, z13.b + __ sve_orv(v25, __ H, p5, z0); // orv h25, p5, z0.h + __ sve_eorv(v25, __ H, p7, z11); // eorv h25, p7, z11.h + __ sve_smaxv(v14, __ H, p5, z22); // smaxv h14, p5, z22.h + __ sve_sminv(v5, __ H, p4, z0); // sminv h5, p4, z0.h + __ sve_fminv(v9, __ D, p0, z3); // fminv d9, p0, z3.d + __ sve_fmaxv(v14, __ S, p1, z29); // fmaxv s14, p1, z29.s + __ sve_fadda(v14, __ D, p5, z4); // fadda d14, p5, d14, z4.d + __ sve_uaddv(v27, __ S, p3, z22); // uaddv d27, p3, z22.s // AddWideNEONOp - __ saddwv(v10, v11, __ T8H, v12, __ T8B); // saddw v10.8H, v11.8H, v12.8B - __ saddwv2(v8, v9, __ T8H, v10, __ T16B); // saddw2 v8.8H, v9.8H, v10.16B - __ saddwv(v9, v10, __ T4S, v11, __ T4H); // saddw v9.4S, v10.4S, v11.4H - __ saddwv2(v19, v20, __ T4S, v21, __ T8H); // saddw2 v19.4S, v20.4S, v21.8H - __ saddwv(v0, v1, __ T2D, v2, __ T2S); // saddw v0.2D, v1.2D, v2.2S - __ saddwv2(v29, v30, __ T2D, v31, __ T4S); // saddw2 v29.2D, v30.2D, v31.4S - __ uaddwv(v16, v17, __ T8H, v18, __ T8B); // uaddw v16.8H, v17.8H, v18.8B - __ uaddwv2(v16, v17, __ T8H, v18, __ T16B); // uaddw2 v16.8H, v17.8H, v18.16B - __ uaddwv(v13, v14, __ T4S, v15, __ T4H); // uaddw v13.4S, v14.4S, v15.4H - __ uaddwv2(v23, v24, __ T4S, v25, __ T8H); // uaddw2 v23.4S, v24.4S, v25.8H - __ uaddwv(v24, v25, __ T2D, v26, __ T2S); // uaddw v24.2D, v25.2D, v26.2S - __ uaddwv2(v23, v24, __ T2D, v25, __ T4S); // uaddw2 v23.2D, v24.2D, v25.4S + __ saddwv(v31, v0, __ T8H, v1, __ T8B); // saddw v31.8H, v0.8H, v1.8B + __ saddwv2(v24, v25, __ T8H, v26, __ T16B); // saddw2 v24.8H, v25.8H, v26.16B + __ saddwv(v11, v12, __ T4S, v13, __ T4H); // saddw v11.4S, v12.4S, v13.4H + __ saddwv2(v16, v17, __ T4S, v18, __ T8H); // saddw2 v16.4S, v17.4S, v18.8H + __ saddwv(v12, v13, __ T2D, v14, __ T2S); // saddw v12.2D, v13.2D, v14.2S + __ saddwv2(v17, v18, __ T2D, v19, __ T4S); // saddw2 v17.2D, v18.2D, v19.4S + __ uaddwv(v28, v29, __ T8H, v30, __ T8B); // uaddw v28.8H, v29.8H, v30.8B + __ uaddwv2(v3, v4, __ T8H, v5, __ T16B); // uaddw2 v3.8H, v4.8H, v5.16B + __ uaddwv(v28, v29, __ T4S, v30, __ T4H); // uaddw v28.4S, v29.4S, v30.4H + __ uaddwv2(v16, v17, __ T4S, v18, __ T8H); // uaddw2 v16.4S, v17.4S, v18.8H + __ uaddwv(v4, v5, __ T2D, v6, __ T2S); // uaddw v4.2D, v5.2D, v6.2S + __ uaddwv2(v29, v30, __ T2D, v31, __ T4S); // uaddw2 v29.2D, v30.2D, v31.4S __ bind(forth); @@ -1387,30 +1403,30 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x1400047d, 0x94000000, - 0x97ffffd4, 0x9400047a, 0x3400000a, 0x34fffa2a, - 0x34008eea, 0x35000008, 0x35fff9c8, 0x35008e88, - 0xb400000b, 0xb4fff96b, 0xb4008e2b, 0xb500001d, - 0xb5fff91d, 0xb5008ddd, 0x10000013, 0x10fff8b3, - 0x10008d73, 0x90000013, 0x36300016, 0x3637f836, - 0x36308cf6, 0x3758000c, 0x375ff7cc, 0x37588c8c, + 0x14000000, 0x17ffffd7, 0x1400048d, 0x94000000, + 0x97ffffd4, 0x9400048a, 0x3400000a, 0x34fffa2a, + 0x340090ea, 0x35000008, 0x35fff9c8, 0x35009088, + 0xb400000b, 0xb4fff96b, 0xb400902b, 0xb500001d, + 0xb5fff91d, 0xb5008fdd, 0x10000013, 0x10fff8b3, + 0x10008f73, 0x90000013, 0x36300016, 0x3637f836, + 0x36308ef6, 0x3758000c, 0x375ff7cc, 0x37588e8c, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x54008a60, 0x54000001, 0x54fff541, 0x54008a01, - 0x54000002, 0x54fff4e2, 0x540089a2, 0x54000002, - 0x54fff482, 0x54008942, 0x54000003, 0x54fff423, - 0x540088e3, 0x54000003, 0x54fff3c3, 0x54008883, - 0x54000004, 0x54fff364, 0x54008824, 0x54000005, - 0x54fff305, 0x540087c5, 0x54000006, 0x54fff2a6, - 0x54008766, 0x54000007, 0x54fff247, 0x54008707, - 0x54000008, 0x54fff1e8, 0x540086a8, 0x54000009, - 0x54fff189, 0x54008649, 0x5400000a, 0x54fff12a, - 0x540085ea, 0x5400000b, 0x54fff0cb, 0x5400858b, - 0x5400000c, 0x54fff06c, 0x5400852c, 0x5400000d, - 0x54fff00d, 0x540084cd, 0x5400000e, 0x54ffefae, - 0x5400846e, 0x5400000f, 0x54ffef4f, 0x5400840f, + 0x54008c60, 0x54000001, 0x54fff541, 0x54008c01, + 0x54000002, 0x54fff4e2, 0x54008ba2, 0x54000002, + 0x54fff482, 0x54008b42, 0x54000003, 0x54fff423, + 0x54008ae3, 0x54000003, 0x54fff3c3, 0x54008a83, + 0x54000004, 0x54fff364, 0x54008a24, 0x54000005, + 0x54fff305, 0x540089c5, 0x54000006, 0x54fff2a6, + 0x54008966, 0x54000007, 0x54fff247, 0x54008907, + 0x54000008, 0x54fff1e8, 0x540088a8, 0x54000009, + 0x54fff189, 0x54008849, 0x5400000a, 0x54fff12a, + 0x540087ea, 0x5400000b, 0x54fff0cb, 0x5400878b, + 0x5400000c, 0x54fff06c, 0x5400872c, 0x5400000d, + 0x54fff00d, 0x540086cd, 0x5400000e, 0x54ffefae, + 0x5400866e, 0x5400000f, 0x54ffef4f, 0x5400860f, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, 0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f, 0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf, @@ -1472,98 +1488,102 @@ 0x9ad521f7, 0x9adb263c, 0x9ac0286a, 0x9ac92f27, 0x9bdd7de6, 0x9b427d4f, 0x1b0b2cf1, 0x1b1ddcf7, 0x9b0b2f6e, 0x9b0cbf04, 0x9b2b728e, 0x9b2cdd6d, - 0x9bae275e, 0x9ba7954d, 0x7ea3d5fe, 0x1e30098c, - 0x1e321bff, 0x1e302ab3, 0x1e35394f, 0x7efcd542, - 0x1e7f0bc7, 0x1e621832, 0x1e632946, 0x1e673979, - 0x1f000d81, 0x1f06dfb3, 0x1f3c6c06, 0x1f2774a2, - 0x1f4d332c, 0x1f48ca78, 0x1f755356, 0x1f7e5853, - 0x1e2042c8, 0x1e20c2b3, 0x1e21424c, 0x1e21c0d5, - 0x1e22c070, 0x1e23c3a3, 0x1ee24383, 0x1e6041cf, - 0x1e60c1aa, 0x1e61424c, 0x1e61c34a, 0x1e6240e7, - 0x1e3803ae, 0x9e3802e0, 0x1e780180, 0x9e7801d7, - 0x1e2200ed, 0x9e2200ef, 0x1e620289, 0x9e620393, - 0x1e24021e, 0x9e640122, 0x1e3002b0, 0x9e70009d, - 0x1e260361, 0x9e660318, 0x1e2702ae, 0x9e6700ad, - 0x1e392180, 0x1e7e2320, 0x1e202388, 0x1e6022a8, - 0x293a1796, 0x29426e73, 0x697c68fc, 0xa93d0486, - 0xa97b5eba, 0x29b47934, 0x29c2534d, 0x69f62dbd, - 0xa9bd54bb, 0xa9c503c6, 0x28a63e13, 0x28e25d2c, - 0x68c469e0, 0xa8b34748, 0xa8f51c59, 0x28264433, - 0x285036c0, 0xa8005f7d, 0xa872290b, 0x0c407160, - 0x4cdfa350, 0x0cd16f56, 0x4cdf27bb, 0x0d40c0d6, - 0x4ddfcbae, 0x0dd0cd96, 0x4c408c01, 0x0cdf86aa, - 0x4d60c327, 0x0dffc929, 0x4deecd89, 0x4cd14887, - 0x0c404a37, 0x4d40e6c4, 0x4ddfe84d, 0x0dcced50, - 0x4cdf0444, 0x0ccb0286, 0x0d60e18c, 0x0dffe630, - 0x0df0eb2e, 0x0e31bab4, 0x4e31b841, 0x0e71bb17, - 0x4e71bbfe, 0x4eb1b9ee, 0x0e30a862, 0x4e30a8e6, - 0x0e70a883, 0x4e70a928, 0x4eb0ab59, 0x6e30f820, - 0x0e31ab9b, 0x2e31abfe, 0x4e31a8c5, 0x6e31a8c5, - 0x0e71abfe, 0x2e71a98b, 0x4e71ab59, 0x6e71a820, - 0x4eb1a81f, 0x6eb1a820, 0x6eb0fa93, 0x7e30fbdd, - 0x7e70fb7a, 0x7eb0f949, 0x7ef0fb7a, 0x0ea0c9ac, - 0x4ea0ca0f, 0x4ee0c98b, 0x2ea0c98b, 0x6ea0ca72, - 0x6ee0cb59, 0x0ea0daf6, 0x4ea0db38, 0x4ee0d820, - 0x0ea0ea51, 0x4ea0e98b, 0x4ee0e8e6, 0x2ea0dbdd, - 0x6ea0d8e6, 0x6ee0d8c5, 0x0e20b8c5, 0x4e20bad5, - 0x0e60ba93, 0x4e60ba30, 0x0ea0ba72, 0x4ea0bbfe, - 0x4ee0bb9b, 0x0ea0fbbc, 0x4ea0f841, 0x4ee0fbbc, - 0x2ea0f841, 0x6ea0fab4, 0x6ee0fbdd, 0x2ea1fa30, - 0x6ea1f9cd, 0x6ee1f96a, 0x2e205bdd, 0x6e205bdd, - 0x0e351e93, 0x4e381ef6, 0x0eac1d6a, 0x4ea61ca4, - 0x2e211c1f, 0x6e371ed5, 0x0e2a8528, 0x4e21841f, - 0x0e758693, 0x4e6c856a, 0x0ebe87bc, 0x4ea48462, - 0x4efb8759, 0x0e270cc5, 0x4e250c83, 0x0e6a0d28, - 0x4e780ef6, 0x0eb50e93, 0x4eaf0dcd, 0x4ee70cc5, - 0x2e3f0fdd, 0x6e3a0f38, 0x2e770ed5, 0x6e7c0f7a, - 0x2eba0f38, 0x6ea50c83, 0x6efa0f38, 0x0e3cd77a, - 0x4e39d717, 0x4e71d60f, 0x2e3786d5, 0x6e258483, - 0x2e7a8738, 0x6e6a8528, 0x2ebb8759, 0x6eb686b4, - 0x6ef28630, 0x0e332e51, 0x4e242c62, 0x0e632c41, - 0x4e622c20, 0x0eba2f38, 0x4ea62ca4, 0x4ee52c83, - 0x2e2e2dac, 0x6e212c1f, 0x2e7e2fbc, 0x6e6c2d6a, - 0x2ebc2f7a, 0x6ea42c62, 0x6eee2dac, 0x0eb4d672, - 0x4ea1d41f, 0x4ee3d441, 0x0e2f9dcd, 0x4e3f9fdd, - 0x0e629c20, 0x4e759e93, 0x0eae9dac, 0x4eb39e51, - 0x2eb8d6f6, 0x6eafd5cd, 0x6efed7bc, 0x2e20d7fe, - 0x6e21d41f, 0x6e63d441, 0x2e3cdf7a, 0x6e3edfbc, - 0x6e66dca4, 0x0e6097fe, 0x4e6694a4, 0x0ea894e6, - 0x4ea097fe, 0x0e3ccf7a, 0x4e34ce72, 0x4e6bcd49, - 0x2e6a9528, 0x6e6e95ac, 0x2ea29420, 0x6eb696b4, - 0x0ea3cc41, 0x4ebacf38, 0x4ee4cc62, 0x2e22fc20, - 0x6e2bfd49, 0x6e7aff38, 0x0e3c677a, 0x4e326630, - 0x0e6067fe, 0x4e656483, 0x0eac656a, 0x4eb96717, - 0x2e2c656a, 0x6e2664a4, 0x2e746672, 0x6e646462, - 0x2ead658b, 0x6eaa6528, 0x0e2ca56a, 0x4e31a60f, - 0x0e73a651, 0x4e64a462, 0x0eaca56a, 0x4eaea5ac, - 0x0e2ef5ac, 0x4e31f60f, 0x4e6ff5cd, 0x0e246c62, - 0x4e296d07, 0x0e766eb4, 0x4e7c6f7a, 0x0eb26e30, - 0x4ea66ca4, 0x2e246c62, 0x6e266ca4, 0x2e6e6dac, - 0x6e746e72, 0x2eb76ed5, 0x6eb26e30, 0x0e34ae72, - 0x4e2dad8b, 0x0e77aed5, 0x4e79af17, 0x0eaeadac, - 0x4ebcaf7a, 0x0e79b717, 0x4e7eb7bc, 0x0eb0b5ee, - 0x4eadb58b, 0x0e3a2738, 0x4e232441, 0x0e6e25ac, - 0x4e61241f, 0x0eac256a, 0x4eb22630, 0x0ea9f507, - 0x4ea4f462, 0x4ee5f483, 0x2eafedcd, 0x6eb5ee93, - 0x6ef3ee51, 0x0fa31041, 0x4f8780c5, 0x4fc41862, - 0x0f895107, 0x4fa1880f, 0x4fcc516a, 0x2f8c916a, - 0x4f9089ee, 0x6fcf99cd, 0x0f748062, 0x4f4d818b, - 0x0fa1800f, 0x4f8880e6, 0x0e2b3549, 0x4e3e37bc, - 0x0e71360f, 0x4e7f37dd, 0x0eb836f6, 0x4ea1341f, - 0x4ef53693, 0x0e213c1f, 0x4e273cc5, 0x0e703dee, - 0x4e743e72, 0x0ea13c1f, 0x4eb43e72, 0x4efd3f9b, - 0x2e368eb4, 0x6e328e30, 0x2e6e8dac, 0x6e6d8d8b, - 0x2eab8d49, 0x6ea88ce6, 0x6ee08ffe, 0x2e333651, - 0x6e3d379b, 0x2e7e37bc, 0x6e6037fe, 0x2ea93507, - 0x6eac356a, 0x6ef636b4, 0x2e2c3d6a, 0x6e263ca4, - 0x2e7a3f38, 0x6e733e51, 0x2eb33e51, 0x6eb83ef6, - 0x6ee53c83, 0x0e3fe7dd, 0x4e31e60f, 0x4e78e6f6, - 0x2eb5e693, 0x6eb5e693, 0x6ef8e6f6, 0x2e24e462, - 0x6e31e60f, 0x6e68e4e6, 0x65922e06, 0x65d0303b, - 0x65903222, 0x659135ab, 0x65913b7e, 0x65d33821, - 0x254b9e29, 0x258f14f7, 0x25c2184c, 0x258222e5, - 0x25d23730, 0x250e9d99, 0x24e9460e, 0x2427465e, - 0x24a2a937, 0x24fbe6ae, 0xba5fd3e3, 0x3a5f03e5, + 0x9bae275e, 0x9ba7954d, 0x7ec315fe, 0x1ef0098c, + 0x1ef21bff, 0x1ef02ab3, 0x1ef5394f, 0x1efc4942, + 0x1eff5bc7, 0x1ee28832, 0x7ea3d546, 0x1e270979, + 0x1e201981, 0x1e3d2a63, 0x1e263ae6, 0x1e3b4b80, + 0x1e2758a2, 0x1e39899d, 0x7ef8d58d, 0x1e720913, + 0x1e751b56, 0x1e622a74, 0x1e683ade, 0x1e754a76, + 0x1e755a4c, 0x1e638a06, 0x1fc373a3, 0x1f0a35cf, + 0x1f0aea4c, 0x1f2f74e7, 0x1f2032e0, 0x1f4d21d8, + 0x1f49d0ef, 0x1f7f43b3, 0x1f705522, 0x1e20409e, + 0x1e20c361, 0x1e214319, 0x1e21c2ae, 0x1e22c0cd, + 0x1e23c32c, 0x1ee243d9, 0x1e6042bc, 0x1e60c2f0, + 0x1e6143a5, 0x1e61c276, 0x1e62428d, 0x1ee1c393, + 0x1e3800d1, 0x9e3800ed, 0x1e78035c, 0x9e7800d1, + 0x1e220081, 0x9e22028e, 0x1e6202a7, 0x9e6202fb, + 0x1e24028d, 0x9e64039e, 0x1e3002aa, 0x9e700225, + 0x1e2601cb, 0x9e6602ad, 0x1e2701db, 0x9e6702e4, + 0x1e3e2300, 0x1e6e2180, 0x1e202228, 0x1e602388, + 0x29021b40, 0x297c78c0, 0x69660970, 0xa908018f, + 0xa9427ae7, 0x29a03cfa, 0x29fc3d4b, 0x69c84033, + 0xa988240e, 0xa9fa0d9b, 0x28a02d88, 0x28c8408a, + 0x68f87a6a, 0xa8ba09f8, 0xa8c52a18, 0x280257be, + 0x28727948, 0xa83868de, 0xa8440a98, 0x0c40733f, + 0x4cdfa1e5, 0x0ccd6cea, 0x4cdf260d, 0x0d40c227, + 0x4ddfcb30, 0x0dc7cc6b, 0x4c408ced, 0x0cdf8769, + 0x4d60c346, 0x0dffca17, 0x4de8cda6, 0x4cda4834, + 0x0c4049ef, 0x4d40e6dd, 0x4ddfe946, 0x0dcfeccf, + 0x4cdf0546, 0x0cc7006b, 0x0d60e32c, 0x0dffe5eb, + 0x0dfce8de, 0x0e31bb9b, 0x4e31bbbc, 0x0e71b841, + 0x4e71bbbc, 0x4eb1b841, 0x0e30aab4, 0x4e30abdd, + 0x0e70aa30, 0x4e70a9cd, 0x4eb0a96a, 0x6e30fbdd, + 0x0e31abdd, 0x2e31aa93, 0x4e31aaf6, 0x6e31a96a, + 0x0e71a8a4, 0x2e71a81f, 0x4e71aad5, 0x6e71a928, + 0x4eb1a81f, 0x6eb1aa93, 0x6eb0f96a, 0x7e30fbbc, + 0x7e70f862, 0x7eb0fb59, 0x7ef0f8c5, 0x0ea0c883, + 0x4ea0c928, 0x4ee0caf6, 0x2ea0ca93, 0x6ea0c9cd, + 0x6ee0c8c5, 0x0ea0dbdd, 0x4ea0db38, 0x4ee0dad5, + 0x0ea0eb7a, 0x4ea0eb38, 0x4ee0e883, 0x2ea0db38, + 0x6ea0db7a, 0x6ee0db17, 0x0e20ba0f, 0x4e20bad5, + 0x0e60b883, 0x4e60bb38, 0x0ea0b928, 0x4ea0bb59, + 0x4ee0bab4, 0x0ea0fa30, 0x4ea0fa51, 0x4ee0f862, + 0x2ea0f841, 0x6ea0f820, 0x6ee0fb38, 0x2ea1f8a4, + 0x6ea1f883, 0x6ee1f9ac, 0x2e20581f, 0x6e205bbc, + 0x0e2c1d6a, 0x4e3c1f7a, 0x0ea41c62, 0x4eae1dac, + 0x2e341e72, 0x6e211c1f, 0x0e238441, 0x4e2f85cd, + 0x0e7f87dd, 0x4e628420, 0x0eb58693, 0x4eae85ac, + 0x4ef38651, 0x0e380ef6, 0x4e2f0dcd, 0x0e7e0fbc, + 0x4e600ffe, 0x0ea10c1f, 0x4ea30c41, 0x4efc0f7a, + 0x2e3e0fbc, 0x6e260ca4, 0x2e600ffe, 0x6e660ca4, + 0x2ea80ce6, 0x6ea00ffe, 0x6efc0f7a, 0x0e34d672, + 0x4e2bd549, 0x4e6ad528, 0x2e2e85ac, 0x6e228420, + 0x2e7686b4, 0x6e638441, 0x2eba8738, 0x6ea48462, + 0x6ee28420, 0x0e2b2d49, 0x4e3a2f38, 0x0e7c2f7a, + 0x4e722e30, 0x0ea02ffe, 0x4ea52c83, 0x4eec2d6a, + 0x2e392f17, 0x6e2c2d6a, 0x2e662ca4, 0x6e742e72, + 0x2ea42c62, 0x6ead2d8b, 0x6eea2d28, 0x0eacd56a, + 0x4eb1d60f, 0x4ef3d651, 0x0e249c62, 0x4e2c9d6a, + 0x0e6e9dac, 0x4e6e9dac, 0x0eb19e0f, 0x4eaf9dcd, + 0x2ea4d462, 0x6ea9d507, 0x6ef6d6b4, 0x2e3cd77a, + 0x6e32d630, 0x6e66d4a4, 0x2e24dc62, 0x6e26dca4, + 0x6e6eddac, 0x0e749672, 0x4e7796d5, 0x0eb29630, + 0x4eb49672, 0x0e2dcd8b, 0x4e37ced5, 0x4e79cf17, + 0x2e6e95ac, 0x6e7c977a, 0x2eb99717, 0x6ebe97bc, + 0x0eb0cdee, 0x4eadcd8b, 0x4efacf38, 0x2e23fc41, + 0x6e2efdac, 0x6e61fc1f, 0x0e2c656a, 0x4e326630, + 0x0e696507, 0x4e646462, 0x0ea56483, 0x4eaf65cd, + 0x2e356693, 0x6e336651, 0x2e726630, 0x6e656483, + 0x2ea36441, 0x6ead658b, 0x0e20a7fe, 0x4e27a4c5, + 0x0e6aa528, 0x4e71a60f, 0x0ebfa7dd, 0x4ea0a7fe, + 0x0e22f420, 0x4e36f6b4, 0x4e69f507, 0x0e366eb4, + 0x4e396f17, 0x0e7e6fbc, 0x4e776ed5, 0x0ebd6f9b, + 0x4ebb6f59, 0x2e276cc5, 0x6e236c41, 0x2e796f17, + 0x6e726e30, 0x2ea16c1f, 0x6ea76cc5, 0x0e2eadac, + 0x4e2bad49, 0x0e7eafbc, 0x4e71ae0f, 0x0ebfafdd, + 0x4eb8aef6, 0x0e61b41f, 0x4e75b693, 0x0ea1b41f, + 0x4ea7b4c5, 0x0e3025ee, 0x4e342672, 0x0e61241f, + 0x4e742672, 0x0ebd279b, 0x4eb626b4, 0x0eb2f630, + 0x4eaef5ac, 0x4eedf58b, 0x2eabed49, 0x6ea8ece6, + 0x6ee0effe, 0x0faf11cd, 0x4fa1880f, 0x4fc710c5, + 0x0fa750c5, 0x4f8e81ac, 0x4fca5928, 0x2fa39041, + 0x4fa98907, 0x6fcb9949, 0x0f6d818b, 0x4f498107, + 0x0f8880e6, 0x4f8788c5, 0x0e2f35cd, 0x4e393717, + 0x0e633441, 0x4e6037fe, 0x0eb53693, 0x4ea734c5, + 0x4ef33651, 0x0e243c62, 0x4e323e30, 0x0e783ef6, + 0x4e6f3dcd, 0x0eac3d6a, 0x4eb73ed5, 0x4eff3fdd, + 0x2e3d8f9b, 0x6e2e8dac, 0x2e7d8f9b, 0x6e658c83, + 0x2ea38c41, 0x6ea18c1f, 0x6efa8f38, 0x2e353693, + 0x6e333651, 0x2e6b3549, 0x6e7e37bc, 0x2ebd379b, + 0x6eb1360f, 0x6ee93507, 0x2e373ed5, 0x6e393f17, + 0x2e613c1f, 0x6e7b3f59, 0x2ea43c62, 0x6ea13c1f, + 0x6efd3f9b, 0x0e34e672, 0x4e2ce56a, 0x4e79e717, + 0x2eb5e693, 0x6ea5e483, 0x6ef4e672, 0x2e22e420, + 0x6e3be759, 0x6e7ce77a, 0x65d22c4b, 0x65d03f92, + 0x65902b68, 0x6591264e, 0x659135f3, 0x65d33444, + 0x25c180af, 0x25cc0897, 0x25c71b6b, 0x25103080, + 0x251729f2, 0x25c48552, 0x24288aab, 0x242213f8, + 0x24fb63d6, 0x247cafab, 0xba5fd3e3, 0x3a5f03e5, 0xfa411be4, 0x7a42cbe2, 0x93df03ff, 0xc820ffff, 0x8822fc7f, 0xc8247cbf, 0x88267fff, 0x4e010fe0, 0x5e040420, 0x4e081fe1, 0x4e0c1fe1, 0x4e0a1fe1, @@ -1625,55 +1645,55 @@ 0x1e721000, 0x1e723000, 0x1e741000, 0x1e743000, 0x1e761000, 0x1e763000, 0x1e781000, 0x1e783000, 0x1e7a1000, 0x1e7a3000, 0x1e7c1000, 0x1e7c3000, - 0x1e7e1000, 0x1e7e3000, 0xf82081f1, 0xf824011a, - 0xf83c1376, 0xf83b22f9, 0xf82030c4, 0xf8305080, - 0xf82f4141, 0xf8277145, 0xf83c6287, 0xf8b780d5, - 0xf8ab0228, 0xf8bf1226, 0xf8a223cc, 0xf8bd3363, - 0xf8b651dd, 0xf8ad423c, 0xf8b87045, 0xf8ae620a, - 0xf8eb82fb, 0xf8ec02c4, 0xf8f11024, 0xf8f321f0, - 0xf8ed318e, 0xf8e25071, 0xf8f540b7, 0xf8e67267, - 0xf8ed623c, 0xf8708046, 0xf87d0083, 0xf8661290, - 0xf86d228c, 0xf8683299, 0xf8735160, 0xf8784286, - 0xf87f720e, 0xf86660e0, 0xb82f8353, 0xb82902ea, - 0xb8351396, 0xb82221e3, 0xb83330f4, 0xb82450fd, - 0xb8204209, 0xb8347097, 0xb83062ea, 0xb8ab80d9, - 0xb8bf01b0, 0xb8b7102c, 0xb8ae22a9, 0xb8b031fa, - 0xb8a451e4, 0xb8a843c6, 0xb8a4723d, 0xb8bd613a, - 0xb8ef8162, 0xb8fd00e3, 0xb8e112bb, 0xb8f0210e, - 0xb8f03336, 0xb8e552b4, 0xb8f04217, 0xb8fe7294, - 0xb8e06264, 0xb8788284, 0xb8640358, 0xb8731102, - 0xb868230e, 0xb87032df, 0xb864503f, 0xb86a4194, - 0xb86070e9, 0xb8786090, 0xce2a6cdb, 0xce107db8, - 0xce748ed6, 0xce8973bf, 0xce7480f4, 0xce6b853c, - 0xcec0818e, 0xce788834, 0x25a0cd89, 0x25a1d093, - 0x05803685, 0x05400c08, 0x050074c4, 0x2560d6a0, - 0x2521c0fb, 0x05805089, 0x05403e98, 0x05025238, - 0x25e0cd0b, 0x25e1d1d2, 0x05800e4e, 0x05402676, - 0x05001e63, 0x25a0d1c9, 0x2521c495, 0x0583abe2, - 0x054011ab, 0x05007cbe, 0x2560c3b7, 0x25e1c358, - 0x05806593, 0x054064b5, 0x05000e5a, 0x2520c3f1, - 0x25a1cc29, 0x05801468, 0x05401d71, 0x05035bb2, - 0x04bb01f0, 0x046806dc, 0x659c0385, 0x65d909e0, - 0x65c30415, 0x04fa10ba, 0x04611a33, 0x042e17ce, - 0x04bf1c52, 0x0456b7d7, 0x04400008, 0x049a1417, - 0x04509b1a, 0x041b1456, 0x0499b58b, 0x04dab938, - 0x04991691, 0x04d395a4, 0x04d19ff6, 0x045011f2, - 0x0417be8d, 0x041eadc1, 0x04980987, 0x052799e4, - 0x05a49c23, 0x04c817e5, 0x044a0d2d, 0x04c901fe, - 0x044b0343, 0x04c10839, 0x04dcac2a, 0x65c087ba, - 0x658d8791, 0x65869d61, 0x65c78021, 0x65828c5b, - 0x049db33e, 0x65c2b862, 0x65c0ac7d, 0x65c1b38e, - 0x65cdab64, 0x65c19022, 0x65fc97e7, 0x65bd162a, - 0x65b82596, 0x65a0a969, 0x65a4d697, 0x65feec8f, - 0x65ba46bb, 0x65a4633f, 0x04c742a6, 0x049f7f18, - 0x042c3141, 0x04b9310d, 0x047733e1, 0x04f53014, - 0x05bb6bbf, 0x05ba6fa8, 0x65c88645, 0x4555b34d, - 0x45cab660, 0x043138c7, 0x44589b94, 0x445a8e71, - 0x44198b1a, 0x449b8f8b, 0x049a3797, 0x04183f14, - 0x045926fb, 0x04c825ac, 0x040a369a, 0x65873fa2, - 0x6586347d, 0x65982b85, 0x04412dd1, 0x0e2c116a, - 0x4e2a1128, 0x0e6b1149, 0x4e751293, 0x0ea21020, - 0x4ebf13dd, 0x2e321230, 0x6e321230, 0x2e6f11cd, - 0x6e791317, 0x2eba1338, 0x6eb91317, + 0x1e7e1000, 0x1e7e3000, 0xf83180b8, 0xf822014e, + 0xf830136b, 0xf837208c, 0xf8363091, 0xf8215213, + 0xf83041cd, 0xf82c7222, 0xf82362f5, 0xf8a580e6, + 0xf8b3038d, 0xf8b110d0, 0xf8a2207d, 0xf8a431e6, + 0xf8b4518d, 0xf8b44328, 0xf8b47013, 0xf8ab60d8, + 0xf8f481df, 0xf8f00006, 0xf8e7126f, 0xf8fa2149, + 0xf8f732d5, 0xf8fc5062, 0xf8ef4293, 0xf8e773a4, + 0xf8e76120, 0xf87082f4, 0xf8640150, 0xf877132b, + 0xf866221f, 0xf86d3197, 0xf861512e, 0xf8754350, + 0xf86f7084, 0xf87060c8, 0xb83e83a4, 0xb831035d, + 0xb829104f, 0xb82b207d, 0xb8273361, 0xb83551d0, + 0xb82842d0, 0xb8397285, 0xb83562f0, 0xb8b0829e, + 0xb8b40080, 0xb8b31098, 0xb8b42304, 0xb8ba3053, + 0xb8a851c8, 0xb8b843f0, 0xb8b673e4, 0xb8a1628a, + 0xb8ec8120, 0xb8e701f8, 0xb8e410db, 0xb8ea231b, + 0xb8ed33f0, 0xb8f65296, 0xb8ff413d, 0xb8ee70f4, + 0xb8f4613c, 0xb86b818e, 0xb8740301, 0xb86911b3, + 0xb8732210, 0xb8653060, 0xb86c51e8, 0xb86f4090, + 0xb86f70be, 0xb86062ca, 0xce20247b, 0xce0a63b3, + 0xce678e84, 0xce8eafb8, 0xce6d836b, 0xce7187f2, + 0xcec0806e, 0xce768a1e, 0x2520d474, 0x2521dae3, + 0x05800d33, 0x05403635, 0x05004cb8, 0x2560d175, + 0x2561c35e, 0x05809863, 0x054030f8, 0x05000ed7, + 0x2520c84e, 0x2521d69a, 0x05809892, 0x05408909, + 0x05000d2c, 0x2560d9cb, 0x25e1d352, 0x05806b49, + 0x0542d157, 0x050026a8, 0x2520cf2a, 0x25a1d599, + 0x05801ec0, 0x05422dc5, 0x05000e11, 0x2560c07e, + 0x2521dfb2, 0x0580ab15, 0x0540040c, 0x0500000f, + 0x04fb0353, 0x043606cd, 0x65940161, 0x65980b14, + 0x65d4063f, 0x04751095, 0x04ff1ade, 0x0473165a, + 0x04bd1dab, 0x0456a1c5, 0x04400542, 0x045a0753, + 0x041083c2, 0x04db0694, 0x0459adbd, 0x045abc2e, + 0x04d9007c, 0x04139929, 0x041189da, 0x04d018f4, + 0x04d7b0d4, 0x045ea3ad, 0x04180029, 0x052799fb, + 0x05e49e24, 0x04080302, 0x040a1dba, 0x04c90e16, + 0x04cb0571, 0x04010210, 0x04dca6fc, 0x65c0915c, + 0x65cd9cf1, 0x65868f04, 0x65878969, 0x65c296c4, + 0x049da1e4, 0x65c2bf44, 0x6580b745, 0x6581a33f, + 0x65cda468, 0x65c19b07, 0x65a19e38, 0x65e81dac, + 0x65f723fd, 0x65e7a2b4, 0x65e8dadd, 0x65e6f4ba, + 0x65b54f52, 0x65bc7140, 0x04d447d1, 0x048e6e3c, + 0x042b334a, 0x04af3160, 0x047432f7, 0x04fd3297, + 0x05a66b60, 0x05646d8d, 0x65c89aff, 0x45ddb046, + 0x4517b7a0, 0x04253904, 0x445891ad, 0x445a8908, + 0x449983b3, 0x44db8ef0, 0x041a3db7, 0x04583419, + 0x04593d79, 0x044836ce, 0x044a3005, 0x65c72069, + 0x658627ae, 0x65d8348e, 0x04812edb, 0x0e21101f, + 0x4e3a1338, 0x0e6d118b, 0x4e721230, 0x0eae11ac, + 0x4eb31251, 0x2e3e13bc, 0x6e251083, 0x2e7e13bc, + 0x6e721230, 0x2ea610a4, 0x6ebf13dd, }; // END Generated code -- do not edit diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ConvF2HFIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ConvF2HFIdealizationTests.java index d7b927778df..6796dc68e52 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ConvF2HFIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ConvF2HFIdealizationTests.java @@ -55,6 +55,9 @@ public static void main(String[] args) { @IR(counts = {IRNode.REINTERPRET_S2HF, ">=1", IRNode.REINTERPRET_HF2S, ">=1", IRNode.ADD_HF, ">=1" }, failOn = {IRNode.ADD_F, IRNode.CONV_HF2F, IRNode.CONV_F2HF}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.REINTERPRET_S2HF, ">=1", IRNode.REINTERPRET_HF2S, ">=1", IRNode.ADD_HF, ">=1" }, + failOn = {IRNode.ADD_F, IRNode.CONV_HF2F, IRNode.CONV_F2HF}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) // Test pattern - ConvHF2F -> AddF -> ConvF2HF is optimized to ReinterpretS2HF -> AddHF -> ReinterpretHF2S public void test1() { for (int i = 0; i < SIZE; i++) { diff --git a/test/hotspot/jtreg/compiler/c2/irTests/MulHFNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/MulHFNodeIdealizationTests.java index eab220dc196..82f43a9a097 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/MulHFNodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/MulHFNodeIdealizationTests.java @@ -56,6 +56,10 @@ public MulHFNodeIdealizationTests() { @IR(counts = {IRNode.ADD_HF, "1"}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}, failOn = {IRNode.MUL_HF}) + @IR(counts = {IRNode.ADD_HF, "1"}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}, + failOn = {IRNode.MUL_HF}) + // Test if x * 2 is optimized to x + x public void test1() { dst = multiply(src, valueOf(2.0f)); } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java b/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java index 014c660dfb2..0acefad5d1d 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java @@ -43,6 +43,8 @@ public class TestFloat16ScalarOperations { private short[] dst; private short res; + private float[] fl; + private static final Float16 ONE = valueOf(1.0f); private static final Float16 MONE = valueOf(-1.0f); private static final Float16 POSITIVE_ZERO = valueOf(0.0f); @@ -76,8 +78,10 @@ public static void main(String args[]) { public TestFloat16ScalarOperations() { src = new short[count]; dst = new short[count]; + fl = new float[count]; for (int i = 0; i < count; i++) { src[i] = Float.floatToFloat16(r.nextFloat() * MAX_VALUE.floatValue()); + fl[i] = r.nextFloat(); } } @@ -99,14 +103,31 @@ static void assertResult(float actual, float expected, String msg, int iter) { } } + @Test + @IR(counts = {"convF2HFAndS2HF", " >0 "}, phase = {CompilePhase.FINAL_CODE}, + applyIfCPUFeature = {"avx512_fp16", "true"}) + @IR(counts = {"convF2HFAndS2HF", " >0 "}, phase = {CompilePhase.FINAL_CODE}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + public void testconvF2HFAndS2HF() { + for (int i = 0; i < count; i++) { + // Transform the pattern (S2HF ConvF2HF) in this IR - + // HF2S (AddHF (S2HF (ConvF2HF fl[i])), (S2HF (ConvF2HF fl[i]))) + // to a single convert operation after matching and eliminate redundant moves + dst[i] = float16ToRawShortBits(add(valueOf(fl[i]), valueOf(fl[i]))); + } + } + @Test @IR(counts = {"convHF2SAndHF2F", " >0 "}, phase = {CompilePhase.FINAL_CODE}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {"convHF2SAndHF2F", " >0 "}, phase = {CompilePhase.FINAL_CODE}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testEliminateIntermediateHF2S() { Float16 res = shortBitsToFloat16((short)0); for (int i = 0; i < count; i++) { // Intermediate HF2S + S2HF is eliminated in following transformation // AddHF S2HF(HF2S (AddHF S2HF(src[i]), S2HF(0))), S2HF(src[i]) => AddHF (AddHF S2HF(src[i]), S2HF(0)), S2HF(src[i]) + // Also, the backend optimizes away the extra move while converting res to a float - ConvHF2F (S2HF (AddHF ..)) res = add(add(res, shortBitsToFloat16(src[i])), shortBitsToFloat16(src[i])); dst[i] = (short)res.floatValue(); } @@ -115,6 +136,8 @@ public void testEliminateIntermediateHF2S() { @Test @IR(counts = {IRNode.ADD_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.ADD_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testAdd1() { Float16 res = shortBitsToFloat16((short)0); for (int i = 0; i < count; i++) { @@ -126,6 +149,8 @@ public void testAdd1() { @Test @IR(failOn = {IRNode.ADD_HF, IRNode.REINTERPRET_S2HF, IRNode.REINTERPRET_HF2S}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(failOn = {IRNode.ADD_HF, IRNode.REINTERPRET_S2HF, IRNode.REINTERPRET_HF2S}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testAdd2() { Float16 hf0 = shortBitsToFloat16((short)0); Float16 hf1 = shortBitsToFloat16((short)15360); @@ -138,6 +163,8 @@ public void testAdd2() { @Test @IR(counts = {IRNode.SUB_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.SUB_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testSub() { Float16 res = shortBitsToFloat16((short)0); for (int i = 0; i < count; i++) { @@ -149,6 +176,8 @@ public void testSub() { @Test @IR(counts = {IRNode.MUL_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.MUL_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testMul() { Float16 res = shortBitsToFloat16((short)0); for (int i = 0; i < count; i++) { @@ -160,6 +189,8 @@ public void testMul() { @Test @IR(counts = {IRNode.DIV_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.DIV_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testDiv() { Float16 res = shortBitsToFloat16((short)0); for (int i = 0; i < count; i++) { @@ -171,6 +202,8 @@ public void testDiv() { @Test @IR(counts = {IRNode.DIV_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.DIV_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testDivByOne() { Float16 res = shortBitsToFloat16((short)0); for (int i = 0; i < count; i++) { @@ -182,6 +215,8 @@ public void testDivByOne() { @Test @IR(counts = {IRNode.MAX_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.MAX_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testMax() { Float16 res = shortBitsToFloat16((short)0); for (int i = 0; i < count; i++) { @@ -193,6 +228,8 @@ public void testMax() { @Test @IR(counts = {IRNode.MIN_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.MIN_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testMin() { Float16 res = shortBitsToFloat16((short)0); for (int i = 0; i < count; i++) { @@ -204,6 +241,8 @@ public void testMin() { @Test @IR(counts = {IRNode.SQRT_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.SQRT_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testSqrt() { Float16 res = shortBitsToFloat16((short)0); for (int i = 0; i < count; i++) { @@ -215,6 +254,8 @@ public void testSqrt() { @Test @IR(counts = {IRNode.FMA_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.FMA_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testFma() { Float16 res = shortBitsToFloat16((short)0); for (int i = 0; i < count; i++) { @@ -227,6 +268,8 @@ public void testFma() { @Test @IR(counts = {IRNode.MUL_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.MUL_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testDivByPOT() { Float16 res = valueOf(0.0f); for (int i = 0; i < 50; i++) { @@ -244,6 +287,8 @@ public void testDivByPOT() { @Test @IR(counts = {IRNode.MUL_HF, " 0 ", IRNode.ADD_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.MUL_HF, " 0 ", IRNode.ADD_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testMulByTWO() { Float16 res = valueOf(0.0f); Float16 multiplier = valueOf(2.0f); @@ -281,6 +326,8 @@ public void testMulByTWO() { @Test @IR(counts = {IRNode.ADD_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.ADD_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testAddConstantFolding() { // If either value is NaN, then the result is NaN. assertResult(add(Float16.NaN, valueOf(2.0f)).floatValue(), Float.NaN, "testAddConstantFolding"); @@ -324,6 +371,8 @@ public void testAddConstantFolding() { @Test @IR(counts = {IRNode.SUB_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.SUB_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testSubConstantFolding() { // If either value is NaN, then the result is NaN. assertResult(subtract(Float16.NaN, valueOf(2.0f)).floatValue(), Float.NaN, "testAddConstantFolding"); @@ -357,6 +406,8 @@ public void testSubConstantFolding() { @Warmup(value = 10000) @IR(counts = {IRNode.MAX_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.MAX_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testMaxConstantFolding() { // If either value is NaN, then the result is NaN. assertResult(max(valueOf(2.0f), Float16.NaN).floatValue(), Float.NaN, "testMaxConstantFolding"); @@ -375,6 +426,8 @@ public void testMaxConstantFolding() { @Test @IR(counts = {IRNode.MIN_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.MIN_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testMinConstantFolding() { // If either value is NaN, then the result is NaN. assertResult(min(valueOf(2.0f), Float16.NaN).floatValue(), Float.NaN, "testMinConstantFolding"); @@ -392,6 +445,8 @@ public void testMinConstantFolding() { @Test @IR(counts = {IRNode.DIV_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.DIV_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testDivConstantFolding() { // If either value is NaN, then the result is NaN. assertResult(divide(Float16.NaN, POSITIVE_ZERO).floatValue(), Float.NaN, "testDivConstantFolding"); @@ -432,6 +487,8 @@ public void testDivConstantFolding() { @Test @IR(counts = {IRNode.MUL_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.MUL_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testMulConstantFolding() { // If any operand is NaN, the result is NaN. assertResult(multiply(Float16.NaN, valueOf(4.0f)).floatValue(), Float.NaN, "testMulConstantFolding"); @@ -455,6 +512,8 @@ public void testMulConstantFolding() { @Test @IR(counts = {IRNode.SQRT_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.SQRT_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testSqrtConstantFolding() { // If the argument is NaN or less than zero, then the result is NaN. assertResult(sqrt(Float16.NaN).floatValue(), Float.NaN, "testSqrtConstantFolding"); @@ -474,6 +533,8 @@ public void testSqrtConstantFolding() { @Test @IR(counts = {IRNode.FMA_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.FMA_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testFMAConstantFolding() { // If any argument is NaN, the result is NaN. assertResult(fma(Float16.NaN, valueOf(2.0f), valueOf(3.0f)).floatValue(), Float.NaN, "testFMAConstantFolding"); @@ -509,6 +570,8 @@ public void testFMAConstantFolding() { @Test @IR(failOn = {IRNode.ADD_HF, IRNode.SUB_HF, IRNode.MUL_HF, IRNode.DIV_HF, IRNode.SQRT_HF, IRNode.FMA_HF}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(failOn = {IRNode.ADD_HF, IRNode.SUB_HF, IRNode.MUL_HF, IRNode.DIV_HF, IRNode.SQRT_HF, IRNode.FMA_HF}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testRounding1() { dst[0] = float16ToRawShortBits(add(RANDOM1, RANDOM2)); dst[1] = float16ToRawShortBits(subtract(RANDOM2, RANDOM3)); @@ -548,6 +611,9 @@ public void checkRounding1() { @IR(counts = {IRNode.ADD_HF, " >0 ", IRNode.SUB_HF, " >0 ", IRNode.MUL_HF, " >0 ", IRNode.DIV_HF, " >0 ", IRNode.SQRT_HF, " >0 ", IRNode.FMA_HF, " >0 "}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.ADD_HF, " >0 ", IRNode.SUB_HF, " >0 ", IRNode.MUL_HF, " >0 ", + IRNode.DIV_HF, " >0 ", IRNode.SQRT_HF, " >0 ", IRNode.FMA_HF, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void testRounding2() { dst[0] = float16ToRawShortBits(add(RANDOM1_VAR, RANDOM2_VAR)); dst[1] = float16ToRawShortBits(subtract(RANDOM2_VAR, RANDOM3_VAR)); diff --git a/test/hotspot/jtreg/compiler/floatingpoint/TestSubNodeFloatDoubleNegation.java b/test/hotspot/jtreg/compiler/floatingpoint/TestSubNodeFloatDoubleNegation.java index 87aeb4489ba..4c7092ec654 100644 --- a/test/hotspot/jtreg/compiler/floatingpoint/TestSubNodeFloatDoubleNegation.java +++ b/test/hotspot/jtreg/compiler/floatingpoint/TestSubNodeFloatDoubleNegation.java @@ -55,9 +55,8 @@ public static void assertResults() { @Test @IR(counts = { IRNode.SUB, "2" }, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"avx512_fp16", "false"}) @IR(counts = { IRNode.SUB_HF, "2" }, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"avx512_fp16", "true"}) - // TODO: uncomment once Float16 support lands in aarch64 with JDK-8345125 - //@IR(counts = { IRNode.SUB, "2" }, applyIfPlatform = {"aarch64", "true"}, applyIfCPUFeatureAnd = {"fphp", "false", "asimdhp", "false"}) - //@IR(counts = { IRNode.SUB_HF, "2" }, applyIfPlatform = {"aarch64", "true"}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + @IR(counts = { IRNode.SUB, "2" }, applyIfPlatform = {"aarch64", "true"}, applyIfCPUFeatureAnd = {"fphp", "false", "asimdhp", "false"}) + @IR(counts = { IRNode.SUB_HF, "2" }, applyIfPlatform = {"aarch64", "true"}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) @IR(counts = { IRNode.SUB, "2" }, applyIfPlatform = {"riscv64", "true"}, applyIfCPUFeature = {"zfh", "false"}) @IR(counts = { IRNode.SUB_HF, "2" }, applyIfPlatform = {"riscv64", "true"}, applyIfCPUFeature = {"zfh", "true"}) @IR(counts = { IRNode.SUB, "2" }, applyIfPlatformAnd = {"x64", "false", "aarch64", "false", "riscv64", "false"}) diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java index 7d229cae152..4ad95ab786f 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java @@ -109,6 +109,8 @@ public class IREncodingPrinter { "asimd", "sve", "sve2", + "fphp", + "asimdhp", // RISCV64 "rvv", "zbkb", diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java index 2cb04c3889b..f061161e93a 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorConvChain.java @@ -45,6 +45,8 @@ public class TestFloat16VectorConvChain { counts = {IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE_ANY, ">= 1", IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE_ANY, " >= 1"}) @IR(applyIfCPUFeatureAnd = {"avx512_fp16", "false", "f16c", "true"}, counts = {IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE_ANY, ">= 1", IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE_ANY, " >= 1"}) + @IR(applyIfCPUFeatureAnd = {"asimd", "true", "fphp", "false", "asimdhp", "false"}, + counts = {IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE_ANY, ">= 1", IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE_ANY, " >= 1"}) public static void test(short [] res, short [] src1, short [] src2) { for (int i = 0; i < res.length; i++) { res[i] = (short)Float.float16ToFloat(Float.floatToFloat16(Float.float16ToFloat(src1[i]) + Float.float16ToFloat(src2[i]))); From db6fa5923cd0394dfb44c7e46c3e7ccc102a933a Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 28 Apr 2025 08:43:14 +0000 Subject: [PATCH 053/118] 8355617: Remove historical debug_only macro in favor of DEBUG_ONLY Reviewed-by: stefank, kbarrett, jwaters --- .../cpu/aarch64/c1_CodeStubs_aarch64.cpp | 10 ++--- src/hotspot/cpu/arm/arm.ad | 8 ++-- src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp | 4 +- .../arm/gc/shared/barrierSetNMethod_arm.cpp | 2 +- src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp | 14 +++---- src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp | 2 +- .../ppc/gc/shared/barrierSetNMethod_ppc.cpp | 2 +- src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp | 10 ++--- src/hotspot/cpu/riscv/nativeInst_riscv.hpp | 2 +- src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp | 12 +++--- src/hotspot/cpu/s390/c1_FrameMap_s390.cpp | 6 +-- src/hotspot/cpu/s390/c1_FrameMap_s390.hpp | 2 +- .../s390/gc/shared/barrierSetNMethod_s390.cpp | 4 +- src/hotspot/cpu/s390/interp_masm_s390.cpp | 20 +++++----- src/hotspot/cpu/x86/assembler_x86.cpp | 40 +++++++++---------- src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp | 12 +++--- src/hotspot/cpu/x86/nativeInst_x86.cpp | 2 +- src/hotspot/cpu/x86/nativeInst_x86.hpp | 2 +- src/hotspot/cpu/x86/x86_64.ad | 4 +- src/hotspot/os/linux/os_linux.cpp | 2 +- src/hotspot/os/posix/signals_posix.cpp | 4 +- src/hotspot/share/asm/assembler.hpp | 2 +- src/hotspot/share/asm/codeBuffer.cpp | 12 +++--- src/hotspot/share/asm/codeBuffer.hpp | 6 +-- src/hotspot/share/c1/c1_FrameMap.hpp | 8 ++-- src/hotspot/share/c1/c1_Runtime1.cpp | 6 +-- src/hotspot/share/ci/ciTypeFlow.cpp | 2 +- src/hotspot/share/ci/ciTypeFlow.hpp | 2 +- src/hotspot/share/ci/ciUtilities.inline.hpp | 6 +-- .../share/classfile/classFileParser.cpp | 4 +- src/hotspot/share/classfile/javaClasses.cpp | 2 +- src/hotspot/share/code/debugInfoRec.cpp | 12 +++--- src/hotspot/share/code/nmethod.cpp | 10 ++--- src/hotspot/share/code/nmethod.hpp | 2 +- src/hotspot/share/code/oopRecorder.cpp | 6 +-- src/hotspot/share/code/relocInfo.cpp | 4 +- src/hotspot/share/code/relocInfo.hpp | 2 +- src/hotspot/share/code/stubs.cpp | 6 +-- src/hotspot/share/compiler/oopMap.cpp | 4 +- src/hotspot/share/compiler/oopMap.hpp | 2 +- .../share/gc/parallel/objectStartArray.cpp | 2 +- .../share/gc/parallel/psParallelCompact.cpp | 2 +- .../share/gc/parallel/psPromotionLAB.cpp | 2 +- .../share/gc/parallel/psPromotionLAB.hpp | 6 +-- .../gc/serial/serialBlockOffsetTable.cpp | 2 +- src/hotspot/share/gc/shared/collectedHeap.hpp | 2 +- .../share/gc/shared/hSpaceCounters.cpp | 2 +- .../share/gc/shared/hSpaceCounters.hpp | 2 +- src/hotspot/share/gc/shared/memAllocator.cpp | 4 +- .../share/gc/shared/scavengableNMethods.cpp | 12 +++--- .../shenandoah/c2/shenandoahBarrierSetC2.cpp | 2 +- .../gc/shenandoah/shenandoahCollectionSet.cpp | 4 +- .../gc/shenandoah/shenandoahTaskqueue.hpp | 8 ++-- src/hotspot/share/interpreter/oopMapCache.cpp | 2 +- .../checkpoint/jfrCheckpointManager.cpp | 2 +- .../share/jfr/recorder/storage/jfrStorage.cpp | 8 ++-- .../share/jfr/utilities/jfrAllocation.cpp | 8 ++-- .../jfr/utilities/jfrDoublyLinkedList.hpp | 2 +- .../share/jfr/writers/jfrMemoryWriterHost.hpp | 4 +- .../writers/jfrMemoryWriterHost.inline.hpp | 8 ++-- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 2 +- .../share/logging/logConfiguration.cpp | 8 ++-- src/hotspot/share/memory/universe.cpp | 4 +- src/hotspot/share/memory/universe.hpp | 6 +-- src/hotspot/share/memory/virtualspace.cpp | 8 ++-- src/hotspot/share/oops/cpCache.hpp | 2 +- src/hotspot/share/oops/generateOopMap.cpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 4 +- src/hotspot/share/oops/instanceRefKlass.cpp | 4 +- src/hotspot/share/oops/klass.cpp | 4 +- src/hotspot/share/oops/method.cpp | 2 +- src/hotspot/share/opto/block.cpp | 2 +- src/hotspot/share/opto/block.hpp | 6 +-- src/hotspot/share/opto/buildOopMap.cpp | 6 +-- src/hotspot/share/opto/callnode.cpp | 12 +++--- src/hotspot/share/opto/cfgnode.cpp | 2 +- src/hotspot/share/opto/chaitin.cpp | 10 ++--- src/hotspot/share/opto/chaitin.hpp | 22 +++++----- src/hotspot/share/opto/compile.cpp | 2 +- src/hotspot/share/opto/escape.cpp | 2 +- src/hotspot/share/opto/graphKit.cpp | 18 ++++----- src/hotspot/share/opto/graphKit.hpp | 6 +-- src/hotspot/share/opto/idealKit.cpp | 4 +- src/hotspot/share/opto/indexSet.cpp | 2 +- src/hotspot/share/opto/loopnode.cpp | 2 +- src/hotspot/share/opto/macro.cpp | 4 +- src/hotspot/share/opto/matcher.cpp | 22 +++++----- src/hotspot/share/opto/memnode.hpp | 10 ++--- src/hotspot/share/opto/multnode.hpp | 2 +- src/hotspot/share/opto/node.cpp | 24 +++++------ src/hotspot/share/opto/node.hpp | 34 ++++++++-------- src/hotspot/share/opto/output.cpp | 2 +- src/hotspot/share/opto/parse1.cpp | 6 +-- src/hotspot/share/opto/phaseX.cpp | 16 ++++---- src/hotspot/share/opto/regalloc.hpp | 4 +- src/hotspot/share/opto/runtime.cpp | 2 +- src/hotspot/share/opto/type.cpp | 2 +- src/hotspot/share/prims/jni.cpp | 14 +++---- src/hotspot/share/prims/jniCheck.cpp | 2 +- src/hotspot/share/prims/jvmtiEnter.xsl | 2 +- src/hotspot/share/prims/jvmtiEnv.cpp | 2 +- src/hotspot/share/prims/jvmtiExport.cpp | 2 +- src/hotspot/share/prims/jvmtiThreadState.cpp | 6 +-- src/hotspot/share/prims/perf.cpp | 8 ++-- src/hotspot/share/prims/upcallLinker.cpp | 4 +- src/hotspot/share/runtime/handles.cpp | 2 +- src/hotspot/share/runtime/handles.hpp | 6 +-- src/hotspot/share/runtime/handles.inline.hpp | 4 +- .../share/runtime/interfaceSupport.inline.hpp | 20 +++++----- src/hotspot/share/runtime/javaCalls.cpp | 4 +- src/hotspot/share/runtime/javaThread.cpp | 4 +- .../share/runtime/jfieldIDWorkaround.hpp | 2 +- src/hotspot/share/runtime/jniHandles.cpp | 6 +-- src/hotspot/share/runtime/os.cpp | 2 +- src/hotspot/share/runtime/thread.cpp | 6 +-- src/hotspot/share/services/heapDumper.cpp | 10 ++--- src/hotspot/share/services/threadService.cpp | 2 +- src/hotspot/share/utilities/growableArray.hpp | 14 +++---- src/hotspot/share/utilities/macros.hpp | 3 -- 119 files changed, 369 insertions(+), 372 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp index 2334cbdff24..2e53ecb8058 100644 --- a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp @@ -69,7 +69,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); return; } @@ -90,7 +90,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ blr(lr); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { @@ -103,7 +103,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void DivByZeroStub::emit_code(LIR_Assembler* ce) { @@ -274,7 +274,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } @@ -289,7 +289,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { } __ far_call(RuntimeAddress(Runtime1::entry_for(_stub)), rscratch2); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index f3b97d23ad3..4a0b557968c 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -1238,11 +1238,11 @@ encode %{ enc_class save_last_PC %{ // preserve mark address mark = __ inst_mark(); - debug_only(int off0 = __ offset()); + DEBUG_ONLY(int off0 = __ offset()); int ret_addr_offset = as_MachCall()->ret_addr_offset(); __ adr(LR, mark + ret_addr_offset); __ str(LR, Address(Rthread, JavaThread::last_Java_pc_offset())); - debug_only(int off1 = __ offset()); + DEBUG_ONLY(int off1 = __ offset()); assert(off1 - off0 == 2 * Assembler::InstructionSize, "correct size prediction"); // restore mark __ set_inst_mark(mark); @@ -1251,11 +1251,11 @@ encode %{ enc_class preserve_SP %{ // preserve mark address mark = __ inst_mark(); - debug_only(int off0 = __ offset()); + DEBUG_ONLY(int off0 = __ offset()); // FP is preserved across all calls, even compiled calls. // Use it to preserve SP in places where the callee might change the SP. __ mov(Rmh_SP_save, SP); - debug_only(int off1 = __ offset()); + DEBUG_ONLY(int off1 = __ offset()); assert(off1 - off0 == 4, "correct size prediction"); // restore mark __ set_inst_mark(mark); diff --git a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp index bca6c7ca30c..5683bc59d5c 100644 --- a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp +++ b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp @@ -59,7 +59,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ call(Runtime1::entry_for(C1StubId::predicate_failed_trap_id), relocInfo::runtime_call_type); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); return; } // Pass the array index on stack because all registers must be preserved @@ -91,7 +91,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { __ call(Runtime1::entry_for(C1StubId::predicate_failed_trap_id), relocInfo::runtime_call_type); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void DivByZeroStub::emit_code(LIR_Assembler* ce) { diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp index c6cc0ce406e..52d71ca65c2 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp @@ -72,7 +72,7 @@ void NativeNMethodBarrier::verify() const { static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) { address barrier_address = nm->code_begin() + nm->frame_complete_offset() - entry_barrier_bytes; NativeNMethodBarrier* barrier = reinterpret_cast(barrier_address); - debug_only(barrier->verify()); + DEBUG_ONLY(barrier->verify()); return barrier; } diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp index d4f5faa29a8..a390a6eeed4 100644 --- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp @@ -74,7 +74,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ bctrl(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); return; } @@ -98,7 +98,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ bctrl(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); } @@ -115,7 +115,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { __ bctrl(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); } @@ -156,7 +156,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) { __ bctrl(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); } @@ -179,7 +179,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { __ bctrl(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); } @@ -193,7 +193,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { __ mtctr(R0); __ bctrl(); ce->add_call_info_here(_info); - debug_only( __ illtrap(); ) + DEBUG_ONLY( __ illtrap(); ) } @@ -441,7 +441,7 @@ void DeoptimizeStub::emit_code(LIR_Assembler* ce) { __ load_const_optimized(R0, _trap_request); // Pass trap request in R0. __ bctrl(); ce->add_call_info_here(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); } diff --git a/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp b/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp index e4684613e25..8ce324a570b 100644 --- a/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp @@ -189,7 +189,7 @@ LIR_Opr FrameMap::_caller_save_fpu_regs[] = {}; FloatRegister FrameMap::nr2floatreg (int rnr) { assert(_init_done, "tables not initialized"); - debug_only(fpu_range_check(rnr);) + DEBUG_ONLY(fpu_range_check(rnr);) return _fpu_regs[rnr]; } diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp index 1b44a169e67..d3bb9cc3c04 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp @@ -108,7 +108,7 @@ static NativeNMethodBarrier* get_nmethod_barrier(nmethod* nm) { } auto barrier = reinterpret_cast(barrier_address); - debug_only(barrier->verify()); + DEBUG_ONLY(barrier->verify()); return barrier; } diff --git a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp index d55521823ec..ea299181ca7 100644 --- a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp @@ -70,7 +70,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); return; } @@ -92,7 +92,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ rt_call(Runtime1::entry_for(stub_id), ra); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { @@ -105,7 +105,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void DivByZeroStub::emit_code(LIR_Assembler* ce) { @@ -258,7 +258,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { @@ -272,7 +272,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { } __ far_call(RuntimeAddress(Runtime1::entry_for(_stub))); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void ArrayCopyStub::emit_code(LIR_Assembler* ce) { diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp index 295e92bbc1b..d8f5fa57816 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp @@ -300,7 +300,7 @@ class NativeGeneralJump: public NativeJump { inline NativeGeneralJump* nativeGeneralJump_at(address addr) { assert_cond(addr != nullptr); NativeGeneralJump* jump = (NativeGeneralJump*)(addr); - debug_only(jump->verify();) + DEBUG_ONLY(jump->verify();) return jump; } diff --git a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp index c858a4b8cb1..430928a66ed 100644 --- a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp +++ b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp @@ -52,7 +52,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { CHECK_BAILOUT(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); return; } @@ -74,7 +74,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { CHECK_BAILOUT(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { @@ -88,7 +88,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { CHECK_BAILOUT(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void CounterOverflowStub::emit_code(LIR_Assembler* ce) { @@ -116,7 +116,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) { ce->emit_call_c(Runtime1::entry_for (C1StubId::throw_div0_exception_id)); CHECK_BAILOUT(); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { @@ -134,7 +134,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { CHECK_BAILOUT(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } // Note: pass object in Z_R1_scratch @@ -147,7 +147,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { ce->emit_call_c(a); CHECK_BAILOUT(); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, C1StubId stub_id) { diff --git a/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp b/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp index 9fa6da8341f..ddba445154a 100644 --- a/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp +++ b/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp @@ -144,13 +144,13 @@ LIR_Opr FrameMap::_caller_save_fpu_regs[] = {}; // c1 rnr -> FloatRegister FloatRegister FrameMap::nr2floatreg (int rnr) { assert(_init_done, "tables not initialized"); - debug_only(fpu_range_check(rnr);) + DEBUG_ONLY(fpu_range_check(rnr);) return _fpu_rnr2reg[rnr]; } void FrameMap::map_float_register(int rnr, FloatRegister reg) { - debug_only(fpu_range_check(rnr);) - debug_only(fpu_range_check(reg->encoding());) + DEBUG_ONLY(fpu_range_check(rnr);) + DEBUG_ONLY(fpu_range_check(reg->encoding());) _fpu_rnr2reg[rnr] = reg; // mapping c1 regnr. -> FloatRegister _fpu_reg2rnr[reg->encoding()] = rnr; // mapping assembler encoding -> c1 regnr. } diff --git a/src/hotspot/cpu/s390/c1_FrameMap_s390.hpp b/src/hotspot/cpu/s390/c1_FrameMap_s390.hpp index 66ccc8de876..721995f41fe 100644 --- a/src/hotspot/cpu/s390/c1_FrameMap_s390.hpp +++ b/src/hotspot/cpu/s390/c1_FrameMap_s390.hpp @@ -107,7 +107,7 @@ static int fpu_reg2rnr (FloatRegister reg) { assert(_init_done, "tables not initialized"); int c1rnr = _fpu_reg2rnr[reg->encoding()]; - debug_only(fpu_range_check(c1rnr);) + DEBUG_ONLY(fpu_range_check(c1rnr);) return c1rnr; } diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp index 85dcc0a4e73..88b3199e4e1 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp @@ -40,7 +40,7 @@ class NativeMethodBarrier: public NativeInstruction { address get_patchable_data_address() const { address inst_addr = get_barrier_start_address() + PATCHABLE_INSTRUCTION_OFFSET; - debug_only(Assembler::is_z_cfi(*((long*)inst_addr))); + DEBUG_ONLY(Assembler::is_z_cfi(*((long*)inst_addr))); return inst_addr + 2; } @@ -91,7 +91,7 @@ static NativeMethodBarrier* get_nmethod_barrier(nmethod* nm) { address barrier_address = nm->code_begin() + nm->frame_complete_offset() - NativeMethodBarrier::BARRIER_TOTAL_LENGTH; auto barrier = reinterpret_cast(barrier_address); - debug_only(barrier->verify()); + DEBUG_ONLY(barrier->verify()); return barrier; } diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index 4ba99eb9e88..09995334330 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -444,7 +444,7 @@ void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, // Useful if consumed previously by access via stackTop(). void InterpreterMacroAssembler::popx(int len) { add2reg(Z_esp, len*Interpreter::stackElementSize); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } // Get Address object of stack top. No checks. No pop. @@ -458,38 +458,38 @@ void InterpreterMacroAssembler::pop_i(Register r) { z_l(r, Interpreter::expr_offset_in_bytes(0), Z_esp); add2reg(Z_esp, Interpreter::stackElementSize); assert_different_registers(r, Z_R1_scratch); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } void InterpreterMacroAssembler::pop_ptr(Register r) { z_lg(r, Interpreter::expr_offset_in_bytes(0), Z_esp); add2reg(Z_esp, Interpreter::stackElementSize); assert_different_registers(r, Z_R1_scratch); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } void InterpreterMacroAssembler::pop_l(Register r) { z_lg(r, Interpreter::expr_offset_in_bytes(0), Z_esp); add2reg(Z_esp, 2*Interpreter::stackElementSize); assert_different_registers(r, Z_R1_scratch); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } void InterpreterMacroAssembler::pop_f(FloatRegister f) { mem2freg_opt(f, Address(Z_esp, Interpreter::expr_offset_in_bytes(0)), false); add2reg(Z_esp, Interpreter::stackElementSize); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } void InterpreterMacroAssembler::pop_d(FloatRegister f) { mem2freg_opt(f, Address(Z_esp, Interpreter::expr_offset_in_bytes(0)), true); add2reg(Z_esp, 2*Interpreter::stackElementSize); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } void InterpreterMacroAssembler::push_i(Register r) { assert_different_registers(r, Z_R1_scratch); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); z_st(r, Address(Z_esp)); add2reg(Z_esp, -Interpreter::stackElementSize); } @@ -501,7 +501,7 @@ void InterpreterMacroAssembler::push_ptr(Register r) { void InterpreterMacroAssembler::push_l(Register r) { assert_different_registers(r, Z_R1_scratch); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); int offset = -Interpreter::stackElementSize; z_stg(r, Address(Z_esp, offset)); clear_mem(Address(Z_esp), Interpreter::stackElementSize); @@ -509,13 +509,13 @@ void InterpreterMacroAssembler::push_l(Register r) { } void InterpreterMacroAssembler::push_f(FloatRegister f) { - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); freg2mem_opt(f, Address(Z_esp), false); add2reg(Z_esp, -Interpreter::stackElementSize); } void InterpreterMacroAssembler::push_d(FloatRegister d) { - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); int offset = -Interpreter::stackElementSize; freg2mem_opt(d, Address(Z_esp, offset)); add2reg(Z_esp, 2 * offset); diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 3ea00681ada..7a4d7c6d6f3 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -801,7 +801,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { address ip = inst; bool is_64bit = false; - debug_only(bool has_disp32 = false); + DEBUG_ONLY(bool has_disp32 = false); int tail_size = 0; // other random bytes (#32, #16, etc.) at end of insn again_after_prefix: @@ -859,7 +859,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x8A: // movb r, a case 0x8B: // movl r, a case 0x8F: // popl a - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); break; case 0x68: // pushq #32 @@ -898,10 +898,10 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x8B: // movw r, a case 0x89: // movw a, r - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); break; case 0xC7: // movw a, #16 - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); tail_size = 2; // the imm16 break; case 0x0F: // several SSE/SSE2 variants @@ -923,7 +923,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x69: // imul r, a, #32 case 0xC7: // movl a, #32(oop?) tail_size = 4; - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0x0F: // movx..., etc. @@ -932,11 +932,11 @@ address Assembler::locate_operand(address inst, WhichOperand which) { tail_size = 1; case 0x38: // ptest, pmovzxbw ip++; // skip opcode - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0x70: // pshufd r, r/a, #8 - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! case 0x73: // psrldq r, #8 tail_size = 1; break; @@ -961,7 +961,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0xAE: // ldmxcsr, stmxcsr, fxrstor, fxsave, clflush case 0xD6: // movq case 0xFE: // paddd - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); break; case 0xAD: // shrd r, a, %cl @@ -976,18 +976,18 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0xC1: // xaddl case 0xC7: // cmpxchg8 case REP16(0x90): // setcc a - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); // fall out of the switch to decode the address break; case 0xC4: // pinsrw r, a, #8 - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); case 0xC5: // pextrw r, r, #8 tail_size = 1; // the imm8 break; case 0xAC: // shrd r, a, #8 - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); tail_size = 1; // the imm8 break; @@ -1004,12 +1004,12 @@ address Assembler::locate_operand(address inst, WhichOperand which) { // also: orl, adcl, sbbl, andl, subl, xorl, cmpl // on 32bit in the case of cmpl, the imm might be an oop tail_size = 4; - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0x83: // addl a, #8; addl r, #8 // also: orl, adcl, sbbl, andl, subl, xorl, cmpl - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! tail_size = 1; break; @@ -1026,7 +1026,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x9B: switch (0xFF & *ip++) { case 0xD9: // fnstcw a - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); break; default: ShouldNotReachHere(); @@ -1045,7 +1045,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x87: // xchg r, a case REP4(0x38): // cmp... case 0x85: // test r, a - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0xA8: // testb rax, #8 @@ -1057,7 +1057,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0xC6: // movb a, #8 case 0x80: // cmpb a, #8 case 0x6B: // imul r, a, #8 - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! tail_size = 1; // the imm8 break; @@ -1109,7 +1109,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { break; } ip++; // skip opcode - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0x62: // EVEX_4bytes @@ -1135,7 +1135,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { break; } ip++; // skip opcode - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0xD1: // sal a, 1; sar a, 1; shl a, 1; shr a, 1 @@ -1147,7 +1147,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0xD8: // fadd_s a; fsubr_s a; fmul_s a; fdivr_s a; fcomp_s a case 0xDC: // fadd_d a; fsubr_d a; fmul_d a; fdivr_d a; fcomp_d a case 0xDE: // faddp_d a; fsubrp_d a; fmulp_d a; fdivrp_d a; fcompp_d a - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); break; case 0xE8: // call rdisp32 @@ -1184,7 +1184,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { default: ip++; } - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; default: diff --git a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp index 73262b21365..7c0d3ff624d 100644 --- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp @@ -68,7 +68,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); return; } @@ -88,7 +88,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ call(RuntimeAddress(Runtime1::entry_for(stub_id))); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { @@ -101,7 +101,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { __ call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void DivByZeroStub::emit_code(LIR_Assembler* ce) { @@ -111,7 +111,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::throw_div0_exception_id))); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } @@ -399,7 +399,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { __ call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } @@ -413,7 +413,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { } __ call(RuntimeAddress(Runtime1::entry_for(_stub))); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } diff --git a/src/hotspot/cpu/x86/nativeInst_x86.cpp b/src/hotspot/cpu/x86/nativeInst_x86.cpp index 4ee741077dc..6e0e078b36e 100644 --- a/src/hotspot/cpu/x86/nativeInst_x86.cpp +++ b/src/hotspot/cpu/x86/nativeInst_x86.cpp @@ -140,7 +140,7 @@ bool NativeCall::is_displacement_aligned() { // Used in the runtime linkage of calls; see class CompiledIC. // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) void NativeCall::set_destination_mt_safe(address dest) { - debug_only(verify()); + DEBUG_ONLY(verify()); // Make sure patching code is locked. No two threads can patch at the same // time but one may be executing this code. assert(CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint() || diff --git a/src/hotspot/cpu/x86/nativeInst_x86.hpp b/src/hotspot/cpu/x86/nativeInst_x86.hpp index d02387aa9ff..f6abadbeb5c 100644 --- a/src/hotspot/cpu/x86/nativeInst_x86.hpp +++ b/src/hotspot/cpu/x86/nativeInst_x86.hpp @@ -503,7 +503,7 @@ class NativeGeneralJump: public NativeInstruction { inline NativeGeneralJump* nativeGeneralJump_at(address address) { NativeGeneralJump* jump = (NativeGeneralJump*)(address); - debug_only(jump->verify();) + DEBUG_ONLY(jump->verify();) return jump; } diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 954a53307c2..25cee7a3094 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -1847,14 +1847,14 @@ encode %{ %} enc_class clear_avx %{ - debug_only(int off0 = __ offset()); + DEBUG_ONLY(int off0 = __ offset()); if (generate_vzeroupper(Compile::current())) { // Clear upper bits of YMM registers to avoid AVX <-> SSE transition penalty // Clear upper bits of YMM registers when current compiled code uses // wide vectors to avoid AVX <-> SSE transition penalty during call. __ vzeroupper(); } - debug_only(int off1 = __ offset()); + DEBUG_ONLY(int off1 = __ offset()); assert(off1 - off0 == clear_avx_size(), "correct size prediction"); %} diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 22d3e1862b5..7061e5ac9d8 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -1662,7 +1662,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { } ThreadInVMfromNative tiv(jt); - debug_only(VMNativeEntryWrapper vew;) + DEBUG_ONLY(VMNativeEntryWrapper vew;) VM_LinuxDllLoad op(filename, ebuf, ebuflen); VMThread::execute(&op); diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 555ac832aae..e900d5695ae 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -147,7 +147,7 @@ class SavedSignalHandlers { }; -debug_only(static bool signal_sets_initialized = false); +DEBUG_ONLY(static bool signal_sets_initialized = false); static sigset_t unblocked_sigs, vm_sigs, preinstalled_sigs; // Our own signal handlers should never ever get replaced by a third party one. @@ -1547,7 +1547,7 @@ static void signal_sets_init() { if (!ReduceSignalUsage) { sigaddset(&vm_sigs, BREAK_SIGNAL); } - debug_only(signal_sets_initialized = true); + DEBUG_ONLY(signal_sets_initialized = true); } // These are signals that are unblocked while a thread is running Java. diff --git a/src/hotspot/share/asm/assembler.hpp b/src/hotspot/share/asm/assembler.hpp index 9abd3eb7171..961b5fab700 100644 --- a/src/hotspot/share/asm/assembler.hpp +++ b/src/hotspot/share/asm/assembler.hpp @@ -73,7 +73,7 @@ class Label; */ class Label { private: - enum { PatchCacheSize = 4 debug_only( +4 ) }; + enum { PatchCacheSize = 4 DEBUG_ONLY( +4 ) }; // _loc encodes both the binding state (via its sign) // and the binding locator (via its value) of a label. diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 917569e2be6..2a9b6215614 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -92,7 +92,7 @@ CodeBuffer::CodeBuffer(CodeBlob* blob) DEBUG_ONLY(: Scrubber(this, sizeof(*this) // Provide code buffer with meaningful name initialize_misc(blob->name()); initialize(blob->content_begin(), blob->content_size()); - debug_only(verify_section_allocation();) + DEBUG_ONLY(verify_section_allocation();) } void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) { @@ -120,7 +120,7 @@ void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) { _insts.initialize_locs(locs_size / sizeof(relocInfo)); } - debug_only(verify_section_allocation();) + DEBUG_ONLY(verify_section_allocation();) } @@ -494,7 +494,7 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const { prev_cs = cs; } - debug_only(dest_cs->_start = nullptr); // defeat double-initialization assert + DEBUG_ONLY(dest_cs->_start = nullptr); // defeat double-initialization assert dest_cs->initialize(buf+buf_offset, csize); dest_cs->set_end(buf+buf_offset+csize); assert(dest_cs->is_allocated(), "must always be allocated"); @@ -505,7 +505,7 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const { // Done calculating sections; did it come out to the right end? assert(buf_offset == total_content_size(), "sanity"); - debug_only(dest->verify_section_allocation();) + DEBUG_ONLY(dest->verify_section_allocation();) } // Append an oop reference that keeps the class alive. @@ -939,11 +939,11 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) { cb.set_blob(nullptr); // Zap the old code buffer contents, to avoid mistakenly using them. - debug_only(Copy::fill_to_bytes(bxp->_total_start, bxp->_total_size, + DEBUG_ONLY(Copy::fill_to_bytes(bxp->_total_start, bxp->_total_size, badCodeHeapFreeVal);) // Make certain that the new sections are all snugly inside the new blob. - debug_only(verify_section_allocation();) + DEBUG_ONLY(verify_section_allocation();) #ifndef PRODUCT _decode_begin = nullptr; // sanity diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index f855d41b181..b38cc74cc3b 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -121,8 +121,8 @@ class CodeSection { _locs_own = false; _scratch_emit = false; _skipped_instructions_size = 0; - debug_only(_index = -1); - debug_only(_outer = (CodeBuffer*)badAddress); + DEBUG_ONLY(_index = -1); + DEBUG_ONLY(_outer = (CodeBuffer*)badAddress); } void initialize_outer(CodeBuffer* outer, int8_t index) { @@ -535,7 +535,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { assert(code_start != nullptr, "sanity"); initialize_misc("static buffer"); initialize(code_start, code_size); - debug_only(verify_section_allocation();) + DEBUG_ONLY(verify_section_allocation();) } // (2) CodeBuffer referring to pre-allocated CodeBlob. diff --git a/src/hotspot/share/c1/c1_FrameMap.hpp b/src/hotspot/share/c1/c1_FrameMap.hpp index 4e4fde0cb4a..f10c4d3f226 100644 --- a/src/hotspot/share/c1/c1_FrameMap.hpp +++ b/src/hotspot/share/c1/c1_FrameMap.hpp @@ -109,19 +109,19 @@ class FrameMap : public CompilationResourceObj { static Register cpu_rnr2reg (int rnr) { assert(_init_done, "tables not initialized"); - debug_only(cpu_range_check(rnr);) + DEBUG_ONLY(cpu_range_check(rnr);) return _cpu_rnr2reg[rnr]; } static int cpu_reg2rnr (Register reg) { assert(_init_done, "tables not initialized"); - debug_only(cpu_range_check(reg->encoding());) + DEBUG_ONLY(cpu_range_check(reg->encoding());) return _cpu_reg2rnr[reg->encoding()]; } static void map_register(int rnr, Register reg) { - debug_only(cpu_range_check(rnr);) - debug_only(cpu_range_check(reg->encoding());) + DEBUG_ONLY(cpu_range_check(rnr);) + DEBUG_ONLY(cpu_range_check(reg->encoding());) _cpu_rnr2reg[rnr] = reg; _cpu_reg2rnr[reg->encoding()] = rnr; } diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 9d4b35024ed..0f87a90a417 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -1363,7 +1363,7 @@ int Runtime1::move_klass_patching(JavaThread* current) { // // NOTE: we are still in Java // - debug_only(NoHandleMark nhm;) + DEBUG_ONLY(NoHandleMark nhm;) { // Enter VM mode ResetNoHandleMark rnhm; @@ -1380,7 +1380,7 @@ int Runtime1::move_mirror_patching(JavaThread* current) { // // NOTE: we are still in Java // - debug_only(NoHandleMark nhm;) + DEBUG_ONLY(NoHandleMark nhm;) { // Enter VM mode ResetNoHandleMark rnhm; @@ -1397,7 +1397,7 @@ int Runtime1::move_appendix_patching(JavaThread* current) { // // NOTE: we are still in Java // - debug_only(NoHandleMark nhm;) + DEBUG_ONLY(NoHandleMark nhm;) { // Enter VM mode ResetNoHandleMark rnhm; diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index 234b4611ea1..6df090a7ce5 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -2924,7 +2924,7 @@ void ciTypeFlow::flow_types() { // Continue flow analysis until fixed point reached - debug_only(int max_block = _next_pre_order;) + DEBUG_ONLY(int max_block = _next_pre_order;) while (!work_list_empty()) { Block* blk = work_list_next(); diff --git a/src/hotspot/share/ci/ciTypeFlow.hpp b/src/hotspot/share/ci/ciTypeFlow.hpp index 92db6253aa0..adfb85dc17f 100644 --- a/src/hotspot/share/ci/ciTypeFlow.hpp +++ b/src/hotspot/share/ci/ciTypeFlow.hpp @@ -253,7 +253,7 @@ class ciTypeFlow : public ArenaObj { set_type_at_tos(type); } void pop() { - debug_only(set_type_at_tos(bottom_type())); + DEBUG_ONLY(set_type_at_tos(bottom_type())); _stack_size--; } ciType* pop_value() { diff --git a/src/hotspot/share/ci/ciUtilities.inline.hpp b/src/hotspot/share/ci/ciUtilities.inline.hpp index 05e73d8ca64..91f848368ac 100644 --- a/src/hotspot/share/ci/ciUtilities.inline.hpp +++ b/src/hotspot/share/ci/ciUtilities.inline.hpp @@ -37,7 +37,7 @@ ThreadInVMfromNative __tiv(thread); \ HandleMarkCleaner __hm(thread); \ JavaThread* THREAD = thread; /* For exception macros. */ \ - debug_only(VMNativeEntryWrapper __vew;) + DEBUG_ONLY(VMNativeEntryWrapper __vew;) @@ -49,10 +49,10 @@ * [TODO] The NoHandleMark line does nothing but declare a function prototype \ * The NoHandkeMark constructor is NOT executed. If the ()'s are \ * removed, causes the NoHandleMark assert to trigger. \ - * debug_only(NoHandleMark __hm();) \ + * DEBUG_ONLY(NoHandleMark __hm();) \ */ \ JavaThread* THREAD = thread; /* For exception macros. */ \ - debug_only(VMNativeEntryWrapper __vew;) + DEBUG_ONLY(VMNativeEntryWrapper __vew;) #define EXCEPTION_CONTEXT \ diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 3e6246d4aee..757f0e72c8c 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -176,7 +176,7 @@ void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const s const ClassFileStream cfs1 = *stream; const ClassFileStream* const cfs = &cfs1; - debug_only(const u1* const old_current = stream->current();) + DEBUG_ONLY(const u1* const old_current = stream->current();) // Used for batching symbol allocations. const char* names[SymbolTable::symbol_alloc_batch_size]; @@ -5243,7 +5243,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, // it's official set_klass(ik); - debug_only(ik->verify();) + DEBUG_ONLY(ik->verify();) } void ClassFileParser::update_class_name(Symbol* new_class_name) { diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index a2ad1dce5e4..a39164232ae 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -4821,7 +4821,7 @@ bool java_lang_ClassLoader::isAncestor(oop loader, oop cl) { assert(is_instance(loader), "loader must be oop"); assert(cl == nullptr || is_instance(cl), "cl argument must be oop"); oop acl = loader; - debug_only(jint loop_count = 0); + DEBUG_ONLY(jint loop_count = 0); // This loop taken verbatim from ClassLoader.java: do { acl = parent(acl); diff --git a/src/hotspot/share/code/debugInfoRec.cpp b/src/hotspot/share/code/debugInfoRec.cpp index 02cd23407bf..8449f5d6929 100644 --- a/src/hotspot/share/code/debugInfoRec.cpp +++ b/src/hotspot/share/code/debugInfoRec.cpp @@ -140,7 +140,7 @@ DebugInformationRecorder::DebugInformationRecorder(OopRecorder* oop_recorder) add_new_pc_offset(PcDesc::lower_offset_limit); // sentinel record - debug_only(_recording_state = rs_null); + DEBUG_ONLY(_recording_state = rs_null); } @@ -159,7 +159,7 @@ void DebugInformationRecorder::add_safepoint(int pc_offset, OopMap* map) { add_new_pc_offset(pc_offset); assert(_recording_state == rs_null, "nesting of recording calls"); - debug_only(_recording_state = rs_safepoint); + DEBUG_ONLY(_recording_state = rs_safepoint); } void DebugInformationRecorder::add_non_safepoint(int pc_offset) { @@ -169,7 +169,7 @@ void DebugInformationRecorder::add_non_safepoint(int pc_offset) { add_new_pc_offset(pc_offset); assert(_recording_state == rs_null, "nesting of recording calls"); - debug_only(_recording_state = rs_non_safepoint); + DEBUG_ONLY(_recording_state = rs_non_safepoint); } void DebugInformationRecorder::add_new_pc_offset(int pc_offset) { @@ -360,7 +360,7 @@ void DebugInformationRecorder::dump_object_pool(GrowableArray* obje void DebugInformationRecorder::end_scopes(int pc_offset, bool is_safepoint) { assert(_recording_state == (is_safepoint? rs_safepoint: rs_non_safepoint), "nesting of recording calls"); - debug_only(_recording_state = rs_null); + DEBUG_ONLY(_recording_state = rs_null); // Try to compress away an equivalent non-safepoint predecessor. // (This only works because we have previously recognized redundant @@ -413,13 +413,13 @@ DebugToken* DebugInformationRecorder::create_monitor_values(GrowableArrayposition(); } int DebugInformationRecorder::pcs_size() { - debug_only(mark_recorders_frozen()); // mark it "frozen" for asserts + DEBUG_ONLY(mark_recorders_frozen()); // mark it "frozen" for asserts if (last_pc()->pc_offset() != PcDesc::upper_offset_limit) add_new_pc_offset(PcDesc::upper_offset_limit); return _pcs_length * sizeof(PcDesc); diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 56ba76a806e..4576a348a4f 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1122,7 +1122,7 @@ nmethod* nmethod::new_native_nmethod(const methodHandle& method, if (nm != nullptr) { // verify nmethod - debug_only(nm->verify();) // might block + DEBUG_ONLY(nm->verify();) // might block nm->log_new_nmethod(); } @@ -1269,7 +1269,7 @@ void nmethod::post_init() { finalize_relocations(); Universe::heap()->register_nmethod(this); - debug_only(Universe::heap()->verify_nmethod(this)); + DEBUG_ONLY(Universe::heap()->verify_nmethod(this)); CodeCache::commit(this); } @@ -1296,7 +1296,7 @@ nmethod::nmethod( _native_basic_lock_sp_offset(basic_lock_sp_offset) { { - debug_only(NoSafepointVerifier nsv;) + DEBUG_ONLY(NoSafepointVerifier nsv;) assert_locked_or_safepoint(CodeCache_lock); init_defaults(code_buffer, offsets); @@ -1437,7 +1437,7 @@ nmethod::nmethod( { assert(debug_info->oop_recorder() == code_buffer->oop_recorder(), "shared OR"); { - debug_only(NoSafepointVerifier nsv;) + DEBUG_ONLY(NoSafepointVerifier nsv;) assert_locked_or_safepoint(CodeCache_lock); init_defaults(code_buffer, offsets); @@ -2802,7 +2802,7 @@ PcDesc* PcDescContainer::find_pc_desc_internal(address pc, bool approximate, add } // Take giant steps at first (4096, then 256, then 16, then 1) - const int LOG2_RADIX = 4 /*smaller steps in debug mode:*/ debug_only(-1); + const int LOG2_RADIX = 4 /*smaller steps in debug mode:*/ DEBUG_ONLY(-1); const int RADIX = (1 << LOG2_RADIX); for (int step = (1 << (LOG2_RADIX*3)); step > 1; step >>= LOG2_RADIX) { while ((mid = lower + step) < upper) { diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 7b19cf75a76..1c536a5d7e1 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -100,7 +100,7 @@ class PcDescCache { typedef PcDesc* PcDescPtr; volatile PcDescPtr _pc_descs[cache_size]; // last cache_size pc_descs found public: - PcDescCache() { debug_only(_pc_descs[0] = nullptr); } + PcDescCache() { DEBUG_ONLY(_pc_descs[0] = nullptr); } void init_to(PcDesc* initial_pc_desc); PcDesc* find_pc_desc(int pc_offset, bool approximate); void add_pc_desc(PcDesc* pc_desc); diff --git a/src/hotspot/share/code/oopRecorder.cpp b/src/hotspot/share/code/oopRecorder.cpp index af23bf12b43..c37651892cc 100644 --- a/src/hotspot/share/code/oopRecorder.cpp +++ b/src/hotspot/share/code/oopRecorder.cpp @@ -122,7 +122,7 @@ template int ValueRecorder::add_handle(T h, bool make_findable) { template int ValueRecorder::maybe_find_index(T h) { - debug_only(_find_index_calls++); + DEBUG_ONLY(_find_index_calls++); assert(!_complete, "cannot allocate more elements after size query"); maybe_initialize(); if (h == nullptr) return null_index; @@ -134,7 +134,7 @@ template int ValueRecorder::maybe_find_index(T h) { return -1; // We know this handle is completely new. } if (cindex >= first_index && _handles->at(cindex - first_index) == h) { - debug_only(_hit_indexes++); + DEBUG_ONLY(_hit_indexes++); return cindex; } if (!_indexes->cache_location_collision(cloc)) { @@ -151,7 +151,7 @@ template int ValueRecorder::maybe_find_index(T h) { if (cloc != nullptr) { _indexes->set_cache_location_index(cloc, findex); } - debug_only(_missed_indexes++); + DEBUG_ONLY(_missed_indexes++); return findex; } } diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index ad194c71bb2..a828a8356aa 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -78,7 +78,7 @@ relocInfo* relocInfo::finish_prefix(short* prefix_limit) { assert(prefix_limit >= p, "must be a valid span of data"); int plen = checked_cast(prefix_limit - p); if (plen == 0) { - debug_only(_value = 0xFFFF); + DEBUG_ONLY(_value = 0xFFFF); return this; // no data: remove self completely } if (plen == 1 && fits_into_immediate(p[0])) { @@ -342,7 +342,7 @@ address Relocation::old_addr_for(address newa, address Relocation::new_addr_for(address olda, const CodeBuffer* src, CodeBuffer* dest) { - debug_only(const CodeBuffer* src0 = src); + DEBUG_ONLY(const CodeBuffer* src0 = src); int sect = CodeBuffer::SECT_NONE; // Look for olda in the source buffer, and all previous incarnations // if the source buffer has been expanded. diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 25cca49e50b..a10f653bbb1 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -574,7 +574,7 @@ class RelocIterator : public StackObj { void set_has_current(bool b) { _datalen = !b ? -1 : 0; - debug_only(_data = nullptr); + DEBUG_ONLY(_data = nullptr); } void set_current(relocInfo& ri) { _current = &ri; diff --git a/src/hotspot/share/code/stubs.cpp b/src/hotspot/share/code/stubs.cpp index 074241ff611..6ae71f93709 100644 --- a/src/hotspot/share/code/stubs.cpp +++ b/src/hotspot/share/code/stubs.cpp @@ -176,14 +176,14 @@ void StubQueue::commit(int committed_code_size) { _queue_end += committed_size; _number_of_stubs++; if (_mutex != nullptr) _mutex->unlock(); - debug_only(stub_verify(s);) + DEBUG_ONLY(stub_verify(s);) } void StubQueue::remove_first() { if (number_of_stubs() == 0) return; Stub* s = first(); - debug_only(stub_verify(s);) + DEBUG_ONLY(stub_verify(s);) stub_finalize(s); _queue_begin += stub_size(s); assert(_queue_begin <= _buffer_limit, "sanity check"); @@ -210,7 +210,7 @@ void StubQueue::remove_first(int n) { void StubQueue::remove_all(){ - debug_only(verify();) + DEBUG_ONLY(verify();) remove_first(number_of_stubs()); assert(number_of_stubs() == 0, "sanity check"); } diff --git a/src/hotspot/share/compiler/oopMap.cpp b/src/hotspot/share/compiler/oopMap.cpp index ea2c770d66f..88249fc8555 100644 --- a/src/hotspot/share/compiler/oopMap.cpp +++ b/src/hotspot/share/compiler/oopMap.cpp @@ -326,7 +326,7 @@ void OopMap::set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional) { assert(reg->value() < _locs_length, "too big reg value for stack size"); assert( _locs_used[reg->value()] == OopMapValue::unused_value, "cannot insert twice" ); - debug_only( _locs_used[reg->value()] = x; ) + DEBUG_ONLY( _locs_used[reg->value()] = x; ) OopMapValue o(reg, x, optional); o.write_on(write_stream()); @@ -511,7 +511,7 @@ void ImmutableOopMap::update_register_map(const frame *fr, RegisterMap *reg_map) // Any reg might be saved by a safepoint handler (see generate_handler_blob). assert( reg_map->_update_for_id == nullptr || fr->is_older(reg_map->_update_for_id), "already updated this map; do not 'update' it twice!" ); - debug_only(reg_map->_update_for_id = fr->id()); + DEBUG_ONLY(reg_map->_update_for_id = fr->id()); // Check if caller must update oop argument assert((reg_map->include_argument_oops() || diff --git a/src/hotspot/share/compiler/oopMap.hpp b/src/hotspot/share/compiler/oopMap.hpp index 634fb8b0bfa..191996f0f05 100644 --- a/src/hotspot/share/compiler/oopMap.hpp +++ b/src/hotspot/share/compiler/oopMap.hpp @@ -162,7 +162,7 @@ class OopMap: public ResourceObj { bool _has_derived_oops; CompressedWriteStream* _write_stream; - debug_only( OopMapValue::oop_types* _locs_used; int _locs_length;) + DEBUG_ONLY( OopMapValue::oop_types* _locs_used; int _locs_length;) // Accessors int omv_count() const { return _omv_count; } diff --git a/src/hotspot/share/gc/parallel/objectStartArray.cpp b/src/hotspot/share/gc/parallel/objectStartArray.cpp index e8d94b28d18..d2c91b302b5 100644 --- a/src/hotspot/share/gc/parallel/objectStartArray.cpp +++ b/src/hotspot/share/gc/parallel/objectStartArray.cpp @@ -121,7 +121,7 @@ void ObjectStartArray::update_for_block_work(HeapWord* blk_start, assert(start_entry_for_region > end_entry, "Sanity check"); } - debug_only(verify_for_block(blk_start, blk_end);) + DEBUG_ONLY(verify_for_block(blk_start, blk_end);) } void ObjectStartArray::verify_for_block(HeapWord* blk_start, HeapWord* blk_end) const { diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index e63ff686312..911384c23bf 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -1629,7 +1629,7 @@ void PSParallelCompact::forward_to_new_addr() { } task(nworkers); ParallelScavengeHeap::heap()->workers().run_task(&task); - debug_only(verify_forward();) + DEBUG_ONLY(verify_forward();) } #ifdef ASSERT diff --git a/src/hotspot/share/gc/parallel/psPromotionLAB.cpp b/src/hotspot/share/gc/parallel/psPromotionLAB.cpp index e3ed819ceb1..a6612d5cd2d 100644 --- a/src/hotspot/share/gc/parallel/psPromotionLAB.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionLAB.cpp @@ -45,7 +45,7 @@ void PSPromotionLAB::initialize(MemRegion lab) { // We can be initialized to a zero size! if (free() > 0) { if (ZapUnusedHeapArea) { - debug_only(Copy::fill_to_words(top(), free()/HeapWordSize, badHeapWord)); + DEBUG_ONLY(Copy::fill_to_words(top(), free()/HeapWordSize, badHeapWord)); } // NOTE! We need to allow space for a filler object. diff --git a/src/hotspot/share/gc/parallel/psPromotionLAB.hpp b/src/hotspot/share/gc/parallel/psPromotionLAB.hpp index e8e42d3754b..60bd4ec250a 100644 --- a/src/hotspot/share/gc/parallel/psPromotionLAB.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionLAB.hpp @@ -55,7 +55,7 @@ class PSPromotionLAB : public CHeapObj { void set_end(HeapWord* value) { _end = value; } // The shared initialize code invokes this. - debug_only(virtual bool lab_is_valid(MemRegion lab) { return false; }); + DEBUG_ONLY(virtual bool lab_is_valid(MemRegion lab) { return false; }); PSPromotionLAB() : _top(nullptr), _bottom(nullptr), _end(nullptr), _state(zero_size) { } @@ -95,7 +95,7 @@ class PSYoungPromotionLAB : public PSPromotionLAB { // Not MT safe inline HeapWord* allocate(size_t size); - debug_only(virtual bool lab_is_valid(MemRegion lab);) + DEBUG_ONLY(virtual bool lab_is_valid(MemRegion lab);) }; class PSOldPromotionLAB : public PSPromotionLAB { @@ -127,7 +127,7 @@ class PSOldPromotionLAB : public PSPromotionLAB { return nullptr; } - debug_only(virtual bool lab_is_valid(MemRegion lab)); + DEBUG_ONLY(virtual bool lab_is_valid(MemRegion lab)); }; #endif // SHARE_GC_PARALLEL_PSPROMOTIONLAB_HPP diff --git a/src/hotspot/share/gc/serial/serialBlockOffsetTable.cpp b/src/hotspot/share/gc/serial/serialBlockOffsetTable.cpp index 5baad7f995a..afaf1aba538 100644 --- a/src/hotspot/share/gc/serial/serialBlockOffsetTable.cpp +++ b/src/hotspot/share/gc/serial/serialBlockOffsetTable.cpp @@ -155,7 +155,7 @@ void SerialBlockOffsetTable::update_for_block_work(HeapWord* blk_start, assert(start_card_for_region > end_card, "Sanity check"); } - debug_only(verify_for_block(blk_start, blk_end);) + DEBUG_ONLY(verify_for_block(blk_start, blk_end);) } HeapWord* SerialBlockOffsetTable::block_start_reaching_into_card(const void* addr) const { diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 439563a4b62..8bf47d6b0bb 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -179,7 +179,7 @@ class CollectedHeap : public CHeapObj { virtual void trace_heap(GCWhen::Type when, const GCTracer* tracer); // Verification functions - debug_only(static void check_for_valid_allocation_state();) + DEBUG_ONLY(static void check_for_valid_allocation_state();) public: enum Name { diff --git a/src/hotspot/share/gc/shared/hSpaceCounters.cpp b/src/hotspot/share/gc/shared/hSpaceCounters.cpp index de5dd2912a5..818d7422fba 100644 --- a/src/hotspot/share/gc/shared/hSpaceCounters.cpp +++ b/src/hotspot/share/gc/shared/hSpaceCounters.cpp @@ -82,7 +82,7 @@ void HSpaceCounters::update_all(size_t capacity, size_t used) { update_used(used); } -debug_only( +DEBUG_ONLY( // for security reasons, we do not allow arbitrary reads from // the counters as they may live in shared memory. jlong HSpaceCounters::used() { diff --git a/src/hotspot/share/gc/shared/hSpaceCounters.hpp b/src/hotspot/share/gc/shared/hSpaceCounters.hpp index 63aabf1479b..01310e456f6 100644 --- a/src/hotspot/share/gc/shared/hSpaceCounters.hpp +++ b/src/hotspot/share/gc/shared/hSpaceCounters.hpp @@ -56,7 +56,7 @@ class HSpaceCounters: public CHeapObj { void update_all(size_t capacity, size_t used); - debug_only( + DEBUG_ONLY( // for security reasons, we do not allow arbitrary reads from // the counters as they may live in shared memory. jlong used(); diff --git a/src/hotspot/share/gc/shared/memAllocator.cpp b/src/hotspot/share/gc/shared/memAllocator.cpp index 74ef1f66184..09ac5d25f86 100644 --- a/src/hotspot/share/gc/shared/memAllocator.cpp +++ b/src/hotspot/share/gc/shared/memAllocator.cpp @@ -145,7 +145,7 @@ void MemAllocator::Allocation::verify_before() { // not take out a lock if from tlab, so clear here. JavaThread* THREAD = _thread; // For exception macros. assert(!HAS_PENDING_EXCEPTION, "Should not allocate with exception pending"); - debug_only(check_for_valid_allocation_state()); + DEBUG_ONLY(check_for_valid_allocation_state()); assert(!Universe::heap()->is_stw_gc_active(), "Allocation during GC pause not allowed"); } @@ -327,7 +327,7 @@ HeapWord* MemAllocator::mem_allocate(Allocation& allocation) const { } // Allocation of an oop can always invoke a safepoint. - debug_only(allocation._thread->check_for_valid_safepoint_state()); + DEBUG_ONLY(allocation._thread->check_for_valid_safepoint_state()); if (UseTLAB) { // Try refilling the TLAB and allocating the object in it. diff --git a/src/hotspot/share/gc/shared/scavengableNMethods.cpp b/src/hotspot/share/gc/shared/scavengableNMethods.cpp index 0dff5526911..887ac5f43a2 100644 --- a/src/hotspot/share/gc/shared/scavengableNMethods.cpp +++ b/src/hotspot/share/gc/shared/scavengableNMethods.cpp @@ -131,13 +131,13 @@ bool ScavengableNMethods::has_scavengable_oops(nmethod* nm) { void ScavengableNMethods::nmethods_do_and_prune(NMethodToOopClosure* cl) { assert_locked_or_safepoint(CodeCache_lock); - debug_only(mark_on_list_nmethods()); + DEBUG_ONLY(mark_on_list_nmethods()); nmethod* prev = nullptr; nmethod* cur = _head; while (cur != nullptr) { ScavengableNMethodsData data = gc_data(cur); - debug_only(data.clear_marked()); + DEBUG_ONLY(data.clear_marked()); assert(data.on_list(), "else shouldn't be on this list"); if (cl != nullptr) { @@ -156,7 +156,7 @@ void ScavengableNMethods::nmethods_do_and_prune(NMethodToOopClosure* cl) { } // Check for stray marks. - debug_only(verify_nmethods()); + DEBUG_ONLY(verify_nmethods()); } void ScavengableNMethods::prune_nmethods_not_into_young() { @@ -166,13 +166,13 @@ void ScavengableNMethods::prune_nmethods_not_into_young() { void ScavengableNMethods::prune_unlinked_nmethods() { assert_locked_or_safepoint(CodeCache_lock); - debug_only(mark_on_list_nmethods()); + DEBUG_ONLY(mark_on_list_nmethods()); nmethod* prev = nullptr; nmethod* cur = _head; while (cur != nullptr) { ScavengableNMethodsData data = gc_data(cur); - debug_only(data.clear_marked()); + DEBUG_ONLY(data.clear_marked()); assert(data.on_list(), "else shouldn't be on this list"); nmethod* const next = data.next(); @@ -187,7 +187,7 @@ void ScavengableNMethods::prune_unlinked_nmethods() { } // Check for stray marks. - debug_only(verify_nmethods()); + DEBUG_ONLY(verify_nmethods()); } // Walk the list of methods which might contain oops to the java heap. diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index d71e84d33b0..f12b3dc5fa8 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -896,7 +896,7 @@ void ShenandoahBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCo uint gc_state_idx = Compile::AliasIdxRaw; const TypePtr* gc_state_adr_type = nullptr; // debug-mode-only argument - debug_only(gc_state_adr_type = phase->C->get_adr_type(gc_state_idx)); + DEBUG_ONLY(gc_state_adr_type = phase->C->get_adr_type(gc_state_idx)); Node* gc_state = phase->transform_later(new LoadBNode(ctrl, mem, gc_state_addr, gc_state_adr_type, TypeInt::BYTE, MemNode::unordered)); Node* stable_and = phase->transform_later(new AndINode(gc_state, phase->igvn().intcon(ShenandoahHeap::HAS_FORWARDED))); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp index 1d353163463..25b900f8d77 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.cpp @@ -190,11 +190,11 @@ void ShenandoahCollectionSet::print_on(outputStream* out) const { byte_size_in_proper_unit(live()), proper_unit_for_byte_size(live()), byte_size_in_proper_unit(used()), proper_unit_for_byte_size(used())); - debug_only(size_t regions = 0;) + DEBUG_ONLY(size_t regions = 0;) for (size_t index = 0; index < _heap->num_regions(); index ++) { if (is_in(index)) { _heap->get_region(index)->print_on(out); - debug_only(regions ++;) + DEBUG_ONLY(regions ++;) } } assert(regions == count(), "Must match"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp index 342b599caf5..af661fd1dc4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp @@ -309,14 +309,14 @@ class ParallelClaimableQueueSet: public GenericTaskQueueSet { volatile jint _claimed_index; shenandoah_padding(1); - debug_only(uint _reserved; ) + DEBUG_ONLY(uint _reserved; ) public: using GenericTaskQueueSet::size; public: ParallelClaimableQueueSet(int n) : GenericTaskQueueSet(n), _claimed_index(0) { - debug_only(_reserved = 0; ) + DEBUG_ONLY(_reserved = 0; ) } void clear_claimed() { _claimed_index = 0; } @@ -326,10 +326,10 @@ class ParallelClaimableQueueSet: public GenericTaskQueueSet { void reserve(uint n) { assert(n <= size(), "Sanity"); _claimed_index = (jint)n; - debug_only(_reserved = n;) + DEBUG_ONLY(_reserved = n;) } - debug_only(uint get_reserved() const { return (uint)_reserved; }) + DEBUG_ONLY(uint get_reserved() const { return (uint)_reserved; }) }; template diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 62ce860594b..e577ce42c1e 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -311,7 +311,7 @@ void OopMapCacheEntry::deallocate_bit_mask() { assert(!Thread::current()->resource_area()->contains((void*)_bit_mask[0]), "This bit mask should not be in the resource area"); FREE_C_HEAP_ARRAY(uintptr_t, _bit_mask[0]); - debug_only(_bit_mask[0] = 0;) + DEBUG_ONLY(_bit_mask[0] = 0;) } } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index 8dbc3d4fcea..7736d3f4565 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -504,7 +504,7 @@ void JfrCheckpointManager::begin_epoch_shift() { void JfrCheckpointManager::end_epoch_shift() { assert(SafepointSynchronize::is_at_safepoint(), "invariant"); - debug_only(const u1 current_epoch = JfrTraceIdEpoch::current();) + DEBUG_ONLY(const u1 current_epoch = JfrTraceIdEpoch::current();) JfrTraceIdEpoch::end_epoch_shift(); assert(current_epoch != JfrTraceIdEpoch::current(), "invariant"); JfrStringPool::on_epoch_shift(); diff --git a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp index a7a21f65944..ca54b297b38 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp @@ -398,7 +398,7 @@ static void assert_flush_large_precondition(ConstBufferPtr cur, const u1* const #endif // ASSERT BufferPtr JfrStorage::flush(BufferPtr cur, size_t used, size_t req, bool native, Thread* t) { - debug_only(assert_flush_precondition(cur, used, native, t);) + DEBUG_ONLY(assert_flush_precondition(cur, used, native, t);) const u1* const cur_pos = cur->pos(); req += used; // requested size now encompass the outstanding used size @@ -407,7 +407,7 @@ BufferPtr JfrStorage::flush(BufferPtr cur, size_t used, size_t req, bool native, } BufferPtr JfrStorage::flush_regular(BufferPtr cur, const u1* const cur_pos, size_t used, size_t req, bool native, Thread* t) { - debug_only(assert_flush_regular_precondition(cur, cur_pos, used, req, t);) + DEBUG_ONLY(assert_flush_regular_precondition(cur, cur_pos, used, req, t);) // A flush is needed before memmove since a non-large buffer is thread stable // (thread local). The flush will not modify memory in addresses above pos() // which is where the "used / uncommitted" data resides. It is therefore both @@ -450,7 +450,7 @@ static BufferPtr restore_shelved_buffer(bool native, Thread* t) { } BufferPtr JfrStorage::flush_large(BufferPtr cur, const u1* const cur_pos, size_t used, size_t req, bool native, Thread* t) { - debug_only(assert_flush_large_precondition(cur, cur_pos, used, req, native, t);) + DEBUG_ONLY(assert_flush_large_precondition(cur, cur_pos, used, req, native, t);) // Can the "regular" buffer (now shelved) accommodate the requested size? BufferPtr shelved = t->jfr_thread_local()->shelved_buffer(); assert(shelved != nullptr, "invariant"); @@ -480,7 +480,7 @@ static BufferPtr large_fail(BufferPtr cur, bool native, JfrStorage& storage_inst // even though it might be smaller than the requested size. // Caller needs to ensure if the size was successfully accommodated. BufferPtr JfrStorage::provision_large(BufferPtr cur, const u1* const cur_pos, size_t used, size_t req, bool native, Thread* t) { - debug_only(assert_provision_large_precondition(cur, used, req, t);) + DEBUG_ONLY(assert_provision_large_precondition(cur, used, req, t);) assert(t->jfr_thread_local()->shelved_buffer() != nullptr, "invariant"); BufferPtr const buffer = acquire_large(req, t); if (buffer == nullptr) { diff --git a/src/hotspot/share/jfr/utilities/jfrAllocation.cpp b/src/hotspot/share/jfr/utilities/jfrAllocation.cpp index f97838c7869..faf0baf2bcb 100644 --- a/src/hotspot/share/jfr/utilities/jfrAllocation.cpp +++ b/src/hotspot/share/jfr/utilities/jfrAllocation.cpp @@ -83,7 +83,7 @@ static void hook_memory_allocation(const char* allocation, size_t alloc_size) { vm_exit_out_of_memory(alloc_size, OOM_MALLOC_ERROR, "AllocateHeap"); } } - debug_only(add(alloc_size)); + DEBUG_ONLY(add(alloc_size)); } void JfrCHeapObj::on_memory_allocation(const void* allocation, size_t size) { @@ -111,12 +111,12 @@ void* JfrCHeapObj::operator new [](size_t size, const std::nothrow_t& nothrow_c } void JfrCHeapObj::operator delete(void* p, size_t size) { - debug_only(hook_memory_deallocation(size);) + DEBUG_ONLY(hook_memory_deallocation(size);) CHeapObj::operator delete(p); } void JfrCHeapObj::operator delete[](void* p, size_t size) { - debug_only(hook_memory_deallocation(size);) + DEBUG_ONLY(hook_memory_deallocation(size);) CHeapObj::operator delete[](p); } @@ -127,7 +127,7 @@ char* JfrCHeapObj::realloc_array(char* old, size_t size) { } void JfrCHeapObj::free(void* p, size_t size) { - debug_only(hook_memory_deallocation(size);) + DEBUG_ONLY(hook_memory_deallocation(size);) FreeHeap(p); } diff --git a/src/hotspot/share/jfr/utilities/jfrDoublyLinkedList.hpp b/src/hotspot/share/jfr/utilities/jfrDoublyLinkedList.hpp index 4e66af7f478..814f15017e0 100644 --- a/src/hotspot/share/jfr/utilities/jfrDoublyLinkedList.hpp +++ b/src/hotspot/share/jfr/utilities/jfrDoublyLinkedList.hpp @@ -205,7 +205,7 @@ void JfrDoublyLinkedList::append_list(T* const head_node, T* const tail_node, } *lt = tail_node; const T* node = head_node; - debug_only(validate_count_param(node, count);) + DEBUG_ONLY(validate_count_param(node, count);) _count += count; assert(tail() == tail_node, "invariant"); assert(in_list(tail_node), "not in list error"); diff --git a/src/hotspot/share/jfr/writers/jfrMemoryWriterHost.hpp b/src/hotspot/share/jfr/writers/jfrMemoryWriterHost.hpp index ad47c954fd7..af87f2bc5fb 100644 --- a/src/hotspot/share/jfr/writers/jfrMemoryWriterHost.hpp +++ b/src/hotspot/share/jfr/writers/jfrMemoryWriterHost.hpp @@ -45,7 +45,7 @@ class ExclusiveAccessAssert { template class MemoryWriterHost : public StorageHost { - debug_only(AccessAssert _access;) + DEBUG_ONLY(AccessAssert _access;) public: typedef typename Adapter::StorageType StorageType; protected: @@ -53,7 +53,7 @@ class MemoryWriterHost : public StorageHost { MemoryWriterHost(StorageType* storage, Thread* thread); MemoryWriterHost(StorageType* storage, size_t size); MemoryWriterHost(Thread* thread); - debug_only(bool is_acquired() const;) + DEBUG_ONLY(bool is_acquired() const;) public: void acquire(); void release(); diff --git a/src/hotspot/share/jfr/writers/jfrMemoryWriterHost.inline.hpp b/src/hotspot/share/jfr/writers/jfrMemoryWriterHost.inline.hpp index 55229e5d732..ad16b7abde3 100644 --- a/src/hotspot/share/jfr/writers/jfrMemoryWriterHost.inline.hpp +++ b/src/hotspot/share/jfr/writers/jfrMemoryWriterHost.inline.hpp @@ -52,18 +52,18 @@ inline MemoryWriterHost::MemoryWriterHost(Thread* thr template inline void MemoryWriterHost::acquire() { - debug_only(_access.acquire();) + DEBUG_ONLY(_access.acquire();) if (!this->is_valid()) { this->flush(); } - debug_only(is_acquired();) + DEBUG_ONLY(is_acquired();) } template inline void MemoryWriterHost::release() { - debug_only(is_acquired();) + DEBUG_ONLY(is_acquired();) StorageHost::release(); - debug_only(_access.release();) + DEBUG_ONLY(_access.release();) } #ifdef ASSERT diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index cffac62c1c8..a4a8f3bb1d0 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -173,7 +173,7 @@ Handle JavaArgumentUnboxer::next_arg(BasicType expectedType) { ThreadInVMfromNative __tiv(thread); \ HandleMarkCleaner __hm(thread); \ JavaThread* THREAD = thread; \ - debug_only(VMNativeEntryWrapper __vew;) + DEBUG_ONLY(VMNativeEntryWrapper __vew;) // Native method block that transitions current thread to '_thread_in_vm'. // Note: CompilerThreadCanCallJava must precede JVMCIENV_FROM_JNI so that diff --git a/src/hotspot/share/logging/logConfiguration.cpp b/src/hotspot/share/logging/logConfiguration.cpp index 662c1f1c2bb..b883dbccacf 100644 --- a/src/hotspot/share/logging/logConfiguration.cpp +++ b/src/hotspot/share/logging/logConfiguration.cpp @@ -59,17 +59,17 @@ class ConfigurationLock : public StackObj { private: // Semaphore used as lock static Semaphore _semaphore; - debug_only(static intx _locking_thread_id;) + DEBUG_ONLY(static intx _locking_thread_id;) public: ConfigurationLock() { _semaphore.wait(); - debug_only(_locking_thread_id = os::current_thread_id()); + DEBUG_ONLY(_locking_thread_id = os::current_thread_id()); } ~ConfigurationLock() { - debug_only(_locking_thread_id = -1); + DEBUG_ONLY(_locking_thread_id = -1); _semaphore.signal(); } - debug_only(static bool current_thread_has_lock();) + DEBUG_ONLY(static bool current_thread_has_lock();) }; Semaphore ConfigurationLock::_semaphore(1); diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index e846eb3ddde..156c96d621f 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -165,8 +165,8 @@ uintx Universe::_the_array_interfaces_bitmap = 0; uintx Universe::_the_empty_klass_bitmap = 0; // These variables are guarded by FullGCALot_lock. -debug_only(OopHandle Universe::_fullgc_alot_dummy_array;) -debug_only(int Universe::_fullgc_alot_dummy_next = 0;) +DEBUG_ONLY(OopHandle Universe::_fullgc_alot_dummy_array;) +DEBUG_ONLY(int Universe::_fullgc_alot_dummy_next = 0;) // Heap int Universe::_verify_count = 0; diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp index 69f8642d6da..35c31330f08 100644 --- a/src/hotspot/share/memory/universe.hpp +++ b/src/hotspot/share/memory/universe.hpp @@ -117,8 +117,8 @@ class Universe: AllStatic { static intptr_t _non_oop_bits; // array of dummy objects used with +FullGCAlot - debug_only(static OopHandle _fullgc_alot_dummy_array;) - debug_only(static int _fullgc_alot_dummy_next;) + DEBUG_ONLY(static OopHandle _fullgc_alot_dummy_array;) + DEBUG_ONLY(static int _fullgc_alot_dummy_next;) // Compiler/dispatch support static int _base_vtable_size; // Java vtbl size of klass Object (in words) @@ -357,7 +357,7 @@ class Universe: AllStatic { // Change the number of dummy objects kept reachable by the full gc dummy // array; this should trigger relocation in a sliding compaction collector. - debug_only(static bool release_fullgc_alot_dummy();) + DEBUG_ONLY(static bool release_fullgc_alot_dummy();) // The non-oop pattern (see compiledIC.hpp, etc) static void* non_oop_word(); static bool contains_non_oop_word(void* p); diff --git a/src/hotspot/share/memory/virtualspace.cpp b/src/hotspot/share/memory/virtualspace.cpp index fa1de208804..2c2d629f032 100644 --- a/src/hotspot/share/memory/virtualspace.cpp +++ b/src/hotspot/share/memory/virtualspace.cpp @@ -200,7 +200,7 @@ static bool commit_expanded(char* start, size_t size, size_t alignment, bool pre return true; } - debug_only(warning( + DEBUG_ONLY(warning( "INFO: os::commit_memory(" PTR_FORMAT ", " PTR_FORMAT " size=%zu, executable=%d) failed", p2i(start), p2i(start + size), size, executable);) @@ -371,7 +371,7 @@ void VirtualSpace::shrink_by(size_t size) { aligned_upper_new_high + upper_needs <= upper_high_boundary(), "must not shrink beyond region"); if (!os::uncommit_memory(aligned_upper_new_high, upper_needs, _executable)) { - debug_only(warning("os::uncommit_memory failed")); + DEBUG_ONLY(warning("os::uncommit_memory failed")); return; } else { _upper_high -= upper_needs; @@ -382,7 +382,7 @@ void VirtualSpace::shrink_by(size_t size) { aligned_middle_new_high + middle_needs <= middle_high_boundary(), "must not shrink beyond region"); if (!os::uncommit_memory(aligned_middle_new_high, middle_needs, _executable)) { - debug_only(warning("os::uncommit_memory failed")); + DEBUG_ONLY(warning("os::uncommit_memory failed")); return; } else { _middle_high -= middle_needs; @@ -393,7 +393,7 @@ void VirtualSpace::shrink_by(size_t size) { aligned_lower_new_high + lower_needs <= lower_high_boundary(), "must not shrink beyond region"); if (!os::uncommit_memory(aligned_lower_new_high, lower_needs, _executable)) { - debug_only(warning("os::uncommit_memory failed")); + DEBUG_ONLY(warning("os::uncommit_memory failed")); return; } else { _lower_high -= lower_needs; diff --git a/src/hotspot/share/oops/cpCache.hpp b/src/hotspot/share/oops/cpCache.hpp index 6490a012e9a..83af4b88e32 100644 --- a/src/hotspot/share/oops/cpCache.hpp +++ b/src/hotspot/share/oops/cpCache.hpp @@ -76,7 +76,7 @@ class ConstantPoolCache: public MetaspaceObj { Array* _resolved_method_entries; // Sizing - debug_only(friend class ClassVerifier;) + DEBUG_ONLY(friend class ClassVerifier;) public: // specific but defiinitions for ldc diff --git a/src/hotspot/share/oops/generateOopMap.cpp b/src/hotspot/share/oops/generateOopMap.cpp index a3db976046d..a17d1ca4e37 100644 --- a/src/hotspot/share/oops/generateOopMap.cpp +++ b/src/hotspot/share/oops/generateOopMap.cpp @@ -2027,7 +2027,7 @@ void GenerateOopMap::ret_jump_targets_do(BytecodeStream *bcs, jmpFct_t jmpFct, i int target_bci = rtEnt->jsrs(i); // Make sure a jrtRet does not set the changed bit for dead basicblock. BasicBlock* jsr_bb = get_basic_block_containing(target_bci - 1); - debug_only(BasicBlock* target_bb = &jsr_bb[1];) + DEBUG_ONLY(BasicBlock* target_bb = &jsr_bb[1];) assert(target_bb == get_basic_block_at(target_bci), "wrong calc. of successor basicblock"); bool alive = jsr_bb->is_alive(); if (TraceNewOopMapGeneration) { diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 715c8f473d0..32445759491 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -1321,7 +1321,7 @@ void InstanceKlass::initialize_impl(TRAPS) { // Step 9 if (!HAS_PENDING_EXCEPTION) { set_initialization_state_and_notify(fully_initialized, CHECK); - debug_only(vtable().verify(tty, true);) + DEBUG_ONLY(vtable().verify(tty, true);) } else { // Step 10 and 11 @@ -4191,7 +4191,7 @@ JNIid::JNIid(Klass* holder, int offset, JNIid* next) { _holder = holder; _offset = offset; _next = next; - debug_only(_is_static_field_id = false;) + DEBUG_ONLY(_is_static_field_id = false;) } diff --git a/src/hotspot/share/oops/instanceRefKlass.cpp b/src/hotspot/share/oops/instanceRefKlass.cpp index eb507495cf5..b8327492493 100644 --- a/src/hotspot/share/oops/instanceRefKlass.cpp +++ b/src/hotspot/share/oops/instanceRefKlass.cpp @@ -71,10 +71,10 @@ void InstanceRefKlass::update_nonstatic_oop_maps(Klass* k) { InstanceKlass* ik = InstanceKlass::cast(k); // Check that we have the right class - debug_only(static bool first_time = true); + DEBUG_ONLY(static bool first_time = true); assert(k == vmClasses::Reference_klass() && first_time, "Invalid update of maps"); - debug_only(first_time = false); + DEBUG_ONLY(first_time = false); assert(ik->nonstatic_oop_map_count() == 1, "just checking"); OopMapBlock* map = ik->start_of_nonstatic_oop_maps(); diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index ac0e125ab4c..b0d2e84335e 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -678,7 +678,7 @@ void Klass::append_to_sibling_list() { if (Universe::is_fully_initialized()) { assert_locked_or_safepoint(Compile_lock); } - debug_only(verify();) + DEBUG_ONLY(verify();) // add ourselves to superklass' subklass list InstanceKlass* super = superklass(); if (super == nullptr) return; // special case: class Object @@ -703,7 +703,7 @@ void Klass::append_to_sibling_list() { return; } } - debug_only(verify();) + DEBUG_ONLY(verify();) } void Klass::clean_subklass() { diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 0c4430b44c3..07f2c559604 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -1256,7 +1256,7 @@ address Method::make_adapters(const methodHandle& mh, TRAPS) { // or adapter that it points to is still live and valid. // This function must not hit a safepoint! address Method::verified_code_entry() { - debug_only(NoSafepointVerifier nsv;) + DEBUG_ONLY(NoSafepointVerifier nsv;) assert(_from_compiled_entry != nullptr, "must be set"); return _from_compiled_entry; } diff --git a/src/hotspot/share/opto/block.cpp b/src/hotspot/share/opto/block.cpp index 5d4ac471303..c33f656047d 100644 --- a/src/hotspot/share/opto/block.cpp +++ b/src/hotspot/share/opto/block.cpp @@ -42,7 +42,7 @@ void Block_Array::grow( uint i ) { if (i < Max()) { return; // No need to grow } - debug_only(_limit = i+1); + DEBUG_ONLY(_limit = i+1); if( i < _size ) return; if( !_size ) { _size = 1; diff --git a/src/hotspot/share/opto/block.hpp b/src/hotspot/share/opto/block.hpp index 4ac6399d3a0..5baa72dfffb 100644 --- a/src/hotspot/share/opto/block.hpp +++ b/src/hotspot/share/opto/block.hpp @@ -48,7 +48,7 @@ struct Tarjan; // allocation I do not need a destructor to reclaim storage. class Block_Array : public ArenaObj { uint _size; // allocated size, as opposed to formal limit - debug_only(uint _limit;) // limit to formal domain + DEBUG_ONLY(uint _limit;) // limit to formal domain Arena *_arena; // Arena to allocate in ReallocMark _nesting; // Safety checks for arena reallocation protected: @@ -57,7 +57,7 @@ class Block_Array : public ArenaObj { public: Block_Array(Arena *a) : _size(OptoBlockListSize), _arena(a) { - debug_only(_limit=0); + DEBUG_ONLY(_limit=0); _blocks = NEW_ARENA_ARRAY( a, Block *, OptoBlockListSize ); for( int i = 0; i < OptoBlockListSize; i++ ) { _blocks[i] = nullptr; @@ -69,7 +69,7 @@ class Block_Array : public ArenaObj { { assert( i < Max(), "oob" ); return _blocks[i]; } // Extend the mapping: index i maps to Block *n. void map( uint i, Block *n ) { grow(i); _blocks[i] = n; } - uint Max() const { debug_only(return _limit); return _size; } + uint Max() const { DEBUG_ONLY(return _limit); return _size; } }; diff --git a/src/hotspot/share/opto/buildOopMap.cpp b/src/hotspot/share/opto/buildOopMap.cpp index f135df21114..675113163e8 100644 --- a/src/hotspot/share/opto/buildOopMap.cpp +++ b/src/hotspot/share/opto/buildOopMap.cpp @@ -191,7 +191,7 @@ void OopFlow::clone( OopFlow *flow, int max_size ) { OopFlow *OopFlow::make( Arena *A, int max_size, Compile* C ) { short *callees = NEW_ARENA_ARRAY(A,short,max_size+1); Node **defs = NEW_ARENA_ARRAY(A,Node*,max_size+1); - debug_only( memset(defs,0,(max_size+1)*sizeof(Node*)) ); + DEBUG_ONLY( memset(defs,0,(max_size+1)*sizeof(Node*)) ); OopFlow *flow = new (A) OopFlow(callees+1, defs+1, C); assert( &flow->_callees[OptoReg::Bad] == callees, "Ok to index at OptoReg::Bad" ); assert( &flow->_defs [OptoReg::Bad] == defs , "Ok to index at OptoReg::Bad" ); @@ -209,7 +209,7 @@ static void clr_live_bit( int *live, int reg ) { OopMap *OopFlow::build_oop_map( Node *n, int max_reg, PhaseRegAlloc *regalloc, int* live ) { int framesize = regalloc->_framesize; int max_inarg_slot = OptoReg::reg2stack(regalloc->_matcher._new_SP); - debug_only( char *dup_check = NEW_RESOURCE_ARRAY(char,OptoReg::stack0()); + DEBUG_ONLY( char *dup_check = NEW_RESOURCE_ARRAY(char,OptoReg::stack0()); memset(dup_check,0,OptoReg::stack0()) ); OopMap *omap = new OopMap( framesize, max_inarg_slot ); @@ -351,7 +351,7 @@ OopMap *OopFlow::build_oop_map( Node *n, int max_reg, PhaseRegAlloc *regalloc, i } else if( OptoReg::is_valid(_callees[reg])) { // callee-save? // It's a callee-save value assert( dup_check[_callees[reg]]==0, "trying to callee save same reg twice" ); - debug_only( dup_check[_callees[reg]]=1; ) + DEBUG_ONLY( dup_check[_callees[reg]]=1; ) VMReg callee = OptoReg::as_VMReg(OptoReg::Name(_callees[reg])); omap->set_callee_saved(r, callee); diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index bb30dcb2976..3527e46c24b 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -266,8 +266,8 @@ JVMState::JVMState(ciMethod* method, JVMState* caller) : assert(method != nullptr, "must be valid call site"); _bci = InvocationEntryBci; _reexecute = Reexecute_Undefined; - debug_only(_bci = -99); // random garbage value - debug_only(_map = (SafePointNode*)-1); + DEBUG_ONLY(_bci = -99); // random garbage value + DEBUG_ONLY(_map = (SafePointNode*)-1); _caller = caller; _depth = 1 + (caller == nullptr ? 0 : caller->depth()); _locoff = TypeFunc::Parms; @@ -281,7 +281,7 @@ JVMState::JVMState(int stack_size) : _method(nullptr) { _bci = InvocationEntryBci; _reexecute = Reexecute_Undefined; - debug_only(_map = (SafePointNode*)-1); + DEBUG_ONLY(_map = (SafePointNode*)-1); _caller = nullptr; _depth = 1; _locoff = TypeFunc::Parms; @@ -323,14 +323,14 @@ bool JVMState::same_calls_as(const JVMState* that) const { //------------------------------debug_start------------------------------------ uint JVMState::debug_start() const { - debug_only(JVMState* jvmroot = of_depth(1)); + DEBUG_ONLY(JVMState* jvmroot = of_depth(1)); assert(jvmroot->locoff() <= this->locoff(), "youngest JVMState must be last"); return of_depth(1)->locoff(); } //-------------------------------debug_end------------------------------------- uint JVMState::debug_end() const { - debug_only(JVMState* jvmroot = of_depth(1)); + DEBUG_ONLY(JVMState* jvmroot = of_depth(1)); assert(jvmroot->endoff() <= this->endoff(), "youngest JVMState must be last"); return endoff(); } @@ -1465,7 +1465,7 @@ void SafePointNode::push_monitor(const FastLockNode *lock) { void SafePointNode::pop_monitor() { // Delete last monitor from debug info - debug_only(int num_before_pop = jvms()->nof_monitors()); + DEBUG_ONLY(int num_before_pop = jvms()->nof_monitors()); const int MonitorEdges = 2; assert(JVMState::logMonitorEdges == exact_log2(MonitorEdges), "correct MonitorEdges"); int scloff = jvms()->scloff(); diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 4885d44a13d..92f6c938dba 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -2233,7 +2233,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { } // One unique input. - debug_only(Node* ident = Identity(phase)); + DEBUG_ONLY(Node* ident = Identity(phase)); // The unique input must eventually be detected by the Identity call. #ifdef ASSERT if (ident != uin && !ident->is_top() && !must_wait_for_region_in_irreducible_loop(phase)) { diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp index 11e1797d034..7832cbd42f8 100644 --- a/src/hotspot/share/opto/chaitin.cpp +++ b/src/hotspot/share/opto/chaitin.cpp @@ -1323,7 +1323,7 @@ void PhaseChaitin::Simplify( ) { bool bound = lrgs(lo_score)._is_bound; // Find cheapest guy - debug_only( int lo_no_simplify=0; ); + DEBUG_ONLY( int lo_no_simplify=0; ); for (uint i = _hi_degree; i; i = lrgs(i)._next) { assert(!_ifg->_yanked->test(i), ""); // It's just vaguely possible to move hi-degree to lo-degree without @@ -1335,7 +1335,7 @@ void PhaseChaitin::Simplify( ) { lo_score = i; break; } - debug_only( if( lrgs(i)._was_lo ) lo_no_simplify=i; ); + DEBUG_ONLY( if( lrgs(i)._was_lo ) lo_no_simplify=i; ); double iscore = lrgs(i).score(); double iarea = lrgs(i)._area; double icost = lrgs(i)._cost; @@ -1577,7 +1577,7 @@ uint PhaseChaitin::Select( ) { // Remove neighbor colors IndexSet *s = _ifg->neighbors(lidx); - debug_only(RegMask orig_mask = lrg->mask();) + DEBUG_ONLY(RegMask orig_mask = lrg->mask();) if (!s->is_empty()) { IndexSetIterator elements(s); @@ -1706,8 +1706,8 @@ uint PhaseChaitin::Select( ) { ttyLocker ttyl; tty->print("L%d spilling with neighbors: ", lidx); s->dump(); - debug_only(tty->print(" original mask: ")); - debug_only(orig_mask.dump()); + DEBUG_ONLY(tty->print(" original mask: ")); + DEBUG_ONLY(orig_mask.dump()); dump_lrg(lidx); } #endif diff --git a/src/hotspot/share/opto/chaitin.hpp b/src/hotspot/share/opto/chaitin.hpp index 4b74420f996..cc3d3479c81 100644 --- a/src/hotspot/share/opto/chaitin.hpp +++ b/src/hotspot/share/opto/chaitin.hpp @@ -82,11 +82,11 @@ class LRG : public ResourceObj { // set makes it not valid. void set_degree( uint degree ) { _eff_degree = degree; - debug_only(_degree_valid = 1;) + DEBUG_ONLY(_degree_valid = 1;) assert(!_mask.is_AllStack() || (_mask.is_AllStack() && lo_degree()), "_eff_degree can't be bigger than AllStack_size - _num_regs if the mask supports stack registers"); } // Made a change that hammered degree - void invalid_degree() { debug_only(_degree_valid=0;) } + void invalid_degree() { DEBUG_ONLY(_degree_valid=0;) } // Incrementally modify degree. If it was correct, it should remain correct void inc_degree( uint mod ) { _eff_degree += mod; @@ -128,15 +128,15 @@ class LRG : public ResourceObj { // count of bits in the current mask. int get_invalid_mask_size() const { return _mask_size; } const RegMask &mask() const { return _mask; } - void set_mask( const RegMask &rm ) { _mask = rm; debug_only(_msize_valid=0;)} - void AND( const RegMask &rm ) { _mask.AND(rm); debug_only(_msize_valid=0;)} - void SUBTRACT( const RegMask &rm ) { _mask.SUBTRACT(rm); debug_only(_msize_valid=0;)} - void Clear() { _mask.Clear() ; debug_only(_msize_valid=1); _mask_size = 0; } - void Set_All() { _mask.Set_All(); debug_only(_msize_valid=1); _mask_size = RegMask::CHUNK_SIZE; } - - void Insert( OptoReg::Name reg ) { _mask.Insert(reg); debug_only(_msize_valid=0;) } - void Remove( OptoReg::Name reg ) { _mask.Remove(reg); debug_only(_msize_valid=0;) } - void clear_to_sets() { _mask.clear_to_sets(_num_regs); debug_only(_msize_valid=0;) } + void set_mask( const RegMask &rm ) { _mask = rm; DEBUG_ONLY(_msize_valid=0;)} + void AND( const RegMask &rm ) { _mask.AND(rm); DEBUG_ONLY(_msize_valid=0;)} + void SUBTRACT( const RegMask &rm ) { _mask.SUBTRACT(rm); DEBUG_ONLY(_msize_valid=0;)} + void Clear() { _mask.Clear() ; DEBUG_ONLY(_msize_valid=1); _mask_size = 0; } + void Set_All() { _mask.Set_All(); DEBUG_ONLY(_msize_valid=1); _mask_size = RegMask::CHUNK_SIZE; } + + void Insert( OptoReg::Name reg ) { _mask.Insert(reg); DEBUG_ONLY(_msize_valid=0;) } + void Remove( OptoReg::Name reg ) { _mask.Remove(reg); DEBUG_ONLY(_msize_valid=0;) } + void clear_to_sets() { _mask.clear_to_sets(_num_regs); DEBUG_ONLY(_msize_valid=0;) } private: // Number of registers this live range uses when it colors diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index e4e82cbddab..effc7e21354 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -474,7 +474,7 @@ void Compile::disconnect_useless_nodes(Unique_Node_List& useful, Unique_Node_Lis remove_useless_late_inlines( &_string_late_inlines, useful); remove_useless_late_inlines( &_boxing_late_inlines, useful); remove_useless_late_inlines(&_vector_reboxing_late_inlines, useful); - debug_only(verify_graph_edges(true /*check for no_dead_code*/, root_and_safepoints);) + DEBUG_ONLY(verify_graph_edges(true /*check for no_dead_code*/, root_and_safepoints);) } // ============================================================================ diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 1fb34e799b2..3a6a81f656e 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -4567,7 +4567,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, } } } else { - debug_only(n->dump();) + DEBUG_ONLY(n->dump();) assert(false, "EA: unexpected node"); continue; } diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index df9177a4938..20feca26ede 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -72,8 +72,8 @@ GraphKit::GraphKit() { _exceptions = nullptr; set_map(nullptr); - debug_only(_sp = -99); - debug_only(set_bci(-99)); + DEBUG_ONLY(_sp = -99); + DEBUG_ONLY(set_bci(-99)); } @@ -196,7 +196,7 @@ bool GraphKit::has_exception_handler() { void GraphKit::set_saved_ex_oop(SafePointNode* ex_map, Node* ex_oop) { assert(!has_saved_ex_oop(ex_map), "clear ex-oop before setting again"); ex_map->add_req(ex_oop); - debug_only(verify_exception_state(ex_map)); + DEBUG_ONLY(verify_exception_state(ex_map)); } inline static Node* common_saved_ex_oop(SafePointNode* ex_map, bool clear_it) { @@ -296,7 +296,7 @@ JVMState* GraphKit::transfer_exceptions_into_jvms() { _map = clone_map(); _map->set_next_exception(nullptr); clear_saved_ex_oop(_map); - debug_only(verify_map()); + DEBUG_ONLY(verify_map()); } else { // ...or created from scratch JVMState* jvms = new (C) JVMState(_method, nullptr); @@ -672,7 +672,7 @@ ciInstance* GraphKit::builtin_throw_exception(Deoptimization::DeoptReason reason //----------------------------PreserveJVMState--------------------------------- PreserveJVMState::PreserveJVMState(GraphKit* kit, bool clone_map) { - debug_only(kit->verify_map()); + DEBUG_ONLY(kit->verify_map()); _kit = kit; _map = kit->map(); // preserve the map _sp = kit->sp(); @@ -780,7 +780,7 @@ void GraphKit::set_map_clone(SafePointNode* m) { _map = m; _map = clone_map(); _map->set_next_exception(nullptr); - debug_only(verify_map()); + DEBUG_ONLY(verify_map()); } @@ -1537,7 +1537,7 @@ Node* GraphKit::memory(uint alias_idx) { Node* GraphKit::reset_memory() { Node* mem = map()->memory(); // do not use this node for any more parsing! - debug_only( map()->set_memory((Node*)nullptr) ); + DEBUG_ONLY( map()->set_memory((Node*)nullptr) ); return _gvn.transform( mem ); } @@ -1574,7 +1574,7 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx = C->get_alias_index(_gvn.type(adr)->isa_ptr()); assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" ); const TypePtr* adr_type = nullptr; // debug-mode-only argument - debug_only(adr_type = C->get_adr_type(adr_idx)); + DEBUG_ONLY(adr_type = C->get_adr_type(adr_idx)); Node* mem = memory(adr_idx); Node* ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency, require_atomic_access, unaligned, mismatched, unsafe, barrier_data); ld = _gvn.transform(ld); @@ -1602,7 +1602,7 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt, int adr_idx = C->get_alias_index(_gvn.type(adr)->isa_ptr()); assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" ); const TypePtr* adr_type = nullptr; - debug_only(adr_type = C->get_adr_type(adr_idx)); + DEBUG_ONLY(adr_type = C->get_adr_type(adr_idx)); Node *mem = memory(adr_idx); Node* st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo, require_atomic_access); if (unaligned) { diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index d1b58526a6d..28773d75333 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -145,7 +145,7 @@ class GraphKit : public Phase { _sp = jvms->sp(); _bci = jvms->bci(); _method = jvms->has_method() ? jvms->method() : nullptr; } - void set_map(SafePointNode* m) { _map = m; debug_only(verify_map()); } + void set_map(SafePointNode* m) { _map = m; DEBUG_ONLY(verify_map()); } void set_sp(int sp) { assert(sp >= 0, "sp must be non-negative: %d", sp); _sp = sp; } void clean_stack(int from_sp); // clear garbage beyond from_sp to top @@ -226,14 +226,14 @@ class GraphKit : public Phase { if (ex_map != nullptr) { _exceptions = ex_map->next_exception(); ex_map->set_next_exception(nullptr); - debug_only(verify_exception_state(ex_map)); + DEBUG_ONLY(verify_exception_state(ex_map)); } return ex_map; } // Add an exception, using the given JVM state, without commoning. void push_exception_state(SafePointNode* ex_map) { - debug_only(verify_exception_state(ex_map)); + DEBUG_ONLY(verify_exception_state(ex_map)); ex_map->set_next_exception(_exceptions); _exceptions = ex_map; } diff --git a/src/hotspot/share/opto/idealKit.cpp b/src/hotspot/share/opto/idealKit.cpp index 8c26e1cc39d..dd7e9ae52b7 100644 --- a/src/hotspot/share/opto/idealKit.cpp +++ b/src/hotspot/share/opto/idealKit.cpp @@ -354,7 +354,7 @@ Node* IdealKit::load(Node* ctl, assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" ); const TypePtr* adr_type = nullptr; // debug-mode-only argument - debug_only(adr_type = C->get_adr_type(adr_idx)); + DEBUG_ONLY(adr_type = C->get_adr_type(adr_idx)); Node* mem = memory(adr_idx); Node* ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency, require_atomic_access); return transform(ld); @@ -366,7 +366,7 @@ Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt, bool mismatched) { assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory"); const TypePtr* adr_type = nullptr; - debug_only(adr_type = C->get_adr_type(adr_idx)); + DEBUG_ONLY(adr_type = C->get_adr_type(adr_idx)); Node *mem = memory(adr_idx); Node* st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo, require_atomic_access); if (mismatched) { diff --git a/src/hotspot/share/opto/indexSet.cpp b/src/hotspot/share/opto/indexSet.cpp index 7f02f01c83f..367f5b78af2 100644 --- a/src/hotspot/share/opto/indexSet.cpp +++ b/src/hotspot/share/opto/indexSet.cpp @@ -121,7 +121,7 @@ IndexSet::BitBlock *IndexSet::alloc_block_containing(uint element) { // Add a BitBlock to the free list. void IndexSet::free_block(uint i) { - debug_only(check_watch("free block", i)); + DEBUG_ONLY(check_watch("free block", i)); assert(i < _max_blocks, "block index too large"); BitBlock *block = _blocks[i]; assert(block != &_empty_block, "cannot free the empty block"); diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index c3f411eea94..195d48b37c6 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -359,7 +359,7 @@ void PhaseIdealLoop::insert_loop_limit_check_predicate(ParsePredicateSuccessProj // for this loop if (TraceLoopLimitCheck) { tty->print_cr("Counted Loop Limit Check generated:"); - debug_only( bol->dump(2); ) + DEBUG_ONLY( bol->dump(2); ) } #endif } diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 1bd35f9dcc9..1fe59c9156b 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -225,7 +225,7 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me if (!ClearArrayNode::step_through(&mem, alloc->_idx, phase)) { // Can not bypass initialization of the instance // we are looking. - debug_only(intptr_t offset;) + DEBUG_ONLY(intptr_t offset;) assert(alloc == AllocateNode::Ideal_allocation(mem->in(3), phase, offset), "sanity"); InitializeNode* init = alloc->as_Allocate()->initialization(); // We are looking for stored value, return Initialize node @@ -1328,7 +1328,7 @@ void PhaseMacroExpand::expand_allocate_common( // No initial test, just fall into next case assert(allocation_has_use || !expand_fast_path, "Should already have been handled"); toobig_false = ctrl; - debug_only(slow_region = NodeSentinel); + DEBUG_ONLY(slow_region = NodeSentinel); } // If we are here there are several possibilities diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index e34a43cc1e2..0849b40ad7e 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -128,7 +128,7 @@ Matcher::Matcher() idealreg2mhdebugmask[Op_RegFlags] = nullptr; idealreg2mhdebugmask[Op_RegVectMask] = nullptr; - debug_only(_mem_node = nullptr;) // Ideal memory node consumed by mach node + DEBUG_ONLY(_mem_node = nullptr;) // Ideal memory node consumed by mach node } //------------------------------warp_incoming_stk_arg------------------------ @@ -1184,7 +1184,7 @@ Node *Matcher::xform( Node *n, int max_stack ) { n->_idx); C->set_node_notes_at(m->_idx, nn); } - debug_only(match_alias_type(C, n, m)); + DEBUG_ONLY(match_alias_type(C, n, m)); } n = m; // n is now a new-space node mstack.set_node(n); @@ -1591,7 +1591,7 @@ MachNode *Matcher::match_tree( const Node *n ) { } } - debug_only( _mem_node = save_mem_node; ) + DEBUG_ONLY( _mem_node = save_mem_node; ) return m; } @@ -1965,9 +1965,9 @@ void Matcher::ReduceInst_Chain_Rule(State* s, int rule, Node* &mem, MachNode* ma assert(newrule >= _LAST_MACH_OPER, "Do NOT chain from internal operand"); mach->_opnds[1] = s->MachOperGenerator(_reduceOp[catch_op]); Node *mem1 = (Node*)1; - debug_only(Node *save_mem_node = _mem_node;) + DEBUG_ONLY(Node *save_mem_node = _mem_node;) mach->add_req( ReduceInst(s, newrule, mem1) ); - debug_only(_mem_node = save_mem_node;) + DEBUG_ONLY(_mem_node = save_mem_node;) } return; } @@ -1979,7 +1979,7 @@ uint Matcher::ReduceInst_Interior( State *s, int rule, Node *&mem, MachNode *mac if( s->_leaf->is_Load() ) { Node *mem2 = s->_leaf->in(MemNode::Memory); assert( mem == (Node*)1 || mem == mem2, "multiple Memories being matched at once?" ); - debug_only( if( mem == (Node*)1 ) _mem_node = s->_leaf;) + DEBUG_ONLY( if( mem == (Node*)1 ) _mem_node = s->_leaf;) mem = mem2; } if( s->_leaf->in(0) != nullptr && s->_leaf->req() > 1) { @@ -2023,9 +2023,9 @@ uint Matcher::ReduceInst_Interior( State *s, int rule, Node *&mem, MachNode *mac // --> ReduceInst( newrule ) mach->_opnds[num_opnds++] = s->MachOperGenerator(_reduceOp[catch_op]); Node *mem1 = (Node*)1; - debug_only(Node *save_mem_node = _mem_node;) + DEBUG_ONLY(Node *save_mem_node = _mem_node;) mach->add_req( ReduceInst( newstate, newrule, mem1 ) ); - debug_only(_mem_node = save_mem_node;) + DEBUG_ONLY(_mem_node = save_mem_node;) } } assert( mach->_opnds[num_opnds-1], "" ); @@ -2056,7 +2056,7 @@ void Matcher::ReduceOper( State *s, int rule, Node *&mem, MachNode *mach ) { if( s->_leaf->is_Load() ) { assert( mem == (Node*)1, "multiple Memories being matched at once?" ); mem = s->_leaf->in(MemNode::Memory); - debug_only(_mem_node = s->_leaf;) + DEBUG_ONLY(_mem_node = s->_leaf;) } handle_precedence_edges(s->_leaf, mach); @@ -2085,9 +2085,9 @@ void Matcher::ReduceOper( State *s, int rule, Node *&mem, MachNode *mach ) { // Reduce the instruction, and add a direct pointer from this // machine instruction to the newly reduced one. Node *mem1 = (Node*)1; - debug_only(Node *save_mem_node = _mem_node;) + DEBUG_ONLY(Node *save_mem_node = _mem_node;) mach->add_req( ReduceInst( kid, newrule, mem1 ) ); - debug_only(_mem_node = save_mem_node;) + DEBUG_ONLY(_mem_node = save_mem_node;) } } } diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 157cc1866a0..a751022f752 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -71,7 +71,7 @@ class MemNode : public Node { _unsafe_access(false), _barrier_data(0) { init_class_id(Class_Mem); - debug_only(_adr_type=at; adr_type();) + DEBUG_ONLY(_adr_type=at; adr_type();) } MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at, Node *c3 ) : Node(c0,c1,c2,c3), @@ -80,7 +80,7 @@ class MemNode : public Node { _unsafe_access(false), _barrier_data(0) { init_class_id(Class_Mem); - debug_only(_adr_type=at; adr_type();) + DEBUG_ONLY(_adr_type=at; adr_type();) } MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at, Node *c3, Node *c4) : Node(c0,c1,c2,c3,c4), @@ -89,7 +89,7 @@ class MemNode : public Node { _unsafe_access(false), _barrier_data(0) { init_class_id(Class_Mem); - debug_only(_adr_type=at; adr_type();) + DEBUG_ONLY(_adr_type=at; adr_type();) } virtual Node* find_previous_arraycopy(PhaseValues* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const { return nullptr; } @@ -273,7 +273,7 @@ class LoadNode : public MemNode { // Following method is copied from TypeNode: void set_type(const Type* t) { assert(t != nullptr, "sanity"); - debug_only(uint check_hash = (VerifyHashTableKeys && _hash_lock) ? hash() : NO_HASH); + DEBUG_ONLY(uint check_hash = (VerifyHashTableKeys && _hash_lock) ? hash() : NO_HASH); *(const Type**)&_type = t; // cast away const-ness // If this node is in the hash table, make sure it doesn't need a rehash. assert(check_hash == NO_HASH || check_hash == hash(), "type change must preserve hash code"); @@ -1497,7 +1497,7 @@ class MergeMemStream : public StackObj { MergeMemStream(MergeMemNode* mm) { mm->iteration_setup(); init(mm); - debug_only(_cnt2 = 999); + DEBUG_ONLY(_cnt2 = 999); } // iterate in parallel over two merges // only iterates through non-empty elements of mm2 diff --git a/src/hotspot/share/opto/multnode.hpp b/src/hotspot/share/opto/multnode.hpp index 25dad70a50a..dff2caed38d 100644 --- a/src/hotspot/share/opto/multnode.hpp +++ b/src/hotspot/share/opto/multnode.hpp @@ -71,7 +71,7 @@ class ProjNode : public Node { // Optimistic setting. Need additional checks in Node::is_dead_loop_safe(). if (con != TypeFunc::Memory || src->is_Start()) init_flags(Flag_is_dead_loop_safe); - debug_only(check_con()); + DEBUG_ONLY(check_con()); } const uint _con; // The field in the tuple we are projecting const bool _is_io_use; // Used to distinguish between the projections diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 76e19360910..a635abebec1 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -322,7 +322,7 @@ Node::Node(uint req) #endif { assert( req < Compile::current()->max_node_limit() - NodeLimitFudgeFactor, "Input limit exceeded" ); - debug_only( verify_construction() ); + DEBUG_ONLY( verify_construction() ); NOT_PRODUCT(nodes_created++); if (req == 0) { _in = nullptr; @@ -341,7 +341,7 @@ Node::Node(Node *n0) , _parse_idx(_idx) #endif { - debug_only( verify_construction() ); + DEBUG_ONLY( verify_construction() ); NOT_PRODUCT(nodes_created++); assert( is_not_dead(n0), "can not use dead node"); _in[0] = n0; if (n0 != nullptr) n0->add_out((Node *)this); @@ -354,7 +354,7 @@ Node::Node(Node *n0, Node *n1) , _parse_idx(_idx) #endif { - debug_only( verify_construction() ); + DEBUG_ONLY( verify_construction() ); NOT_PRODUCT(nodes_created++); assert( is_not_dead(n0), "can not use dead node"); assert( is_not_dead(n1), "can not use dead node"); @@ -369,7 +369,7 @@ Node::Node(Node *n0, Node *n1, Node *n2) , _parse_idx(_idx) #endif { - debug_only( verify_construction() ); + DEBUG_ONLY( verify_construction() ); NOT_PRODUCT(nodes_created++); assert( is_not_dead(n0), "can not use dead node"); assert( is_not_dead(n1), "can not use dead node"); @@ -386,7 +386,7 @@ Node::Node(Node *n0, Node *n1, Node *n2, Node *n3) , _parse_idx(_idx) #endif { - debug_only( verify_construction() ); + DEBUG_ONLY( verify_construction() ); NOT_PRODUCT(nodes_created++); assert( is_not_dead(n0), "can not use dead node"); assert( is_not_dead(n1), "can not use dead node"); @@ -405,7 +405,7 @@ Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, Node *n4) , _parse_idx(_idx) #endif { - debug_only( verify_construction() ); + DEBUG_ONLY( verify_construction() ); NOT_PRODUCT(nodes_created++); assert( is_not_dead(n0), "can not use dead node"); assert( is_not_dead(n1), "can not use dead node"); @@ -427,7 +427,7 @@ Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, , _parse_idx(_idx) #endif { - debug_only( verify_construction() ); + DEBUG_ONLY( verify_construction() ); NOT_PRODUCT(nodes_created++); assert( is_not_dead(n0), "can not use dead node"); assert( is_not_dead(n1), "can not use dead node"); @@ -451,7 +451,7 @@ Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, , _parse_idx(_idx) #endif { - debug_only( verify_construction() ); + DEBUG_ONLY( verify_construction() ); NOT_PRODUCT(nodes_created++); assert( is_not_dead(n0), "can not use dead node"); assert( is_not_dead(n1), "can not use dead node"); @@ -489,7 +489,7 @@ Node *Node::clone() const { n->_outcnt = 0; n->_outmax = 0; // Unlock this guy, since he is not in any hash table. - debug_only(n->_hash_lock = 0); + DEBUG_ONLY(n->_hash_lock = 0); // Walk the old node's input list to duplicate its edges uint i; for( i = 0; i < len(); i++ ) { @@ -525,11 +525,11 @@ Node *Node::clone() const { n->set_idx(C->next_unique()); // Get new unique index as well NOT_PRODUCT(n->_igv_idx = C->next_igv_idx()); - debug_only( n->verify_construction() ); + DEBUG_ONLY( n->verify_construction() ); NOT_PRODUCT(nodes_created++); // Do not patch over the debug_idx of a clone, because it makes it // impossible to break on the clone's moment of creation. - //debug_only( n->set_debug_idx( debug_idx() ) ); + //DEBUG_ONLY( n->set_debug_idx( debug_idx() ) ); C->copy_node_notes_to(n, (Node*) this); @@ -942,7 +942,7 @@ void Node::disconnect_inputs(Compile* C) { #endif // Node::destruct requires all out edges be deleted first - // debug_only(destruct();) // no reuse benefit expected + // DEBUG_ONLY(destruct();) // no reuse benefit expected C->record_dead_node(_idx); } diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 1cb9009ef27..e1a4ee22661 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -427,11 +427,11 @@ class Node { assert(_outcnt > 0,"oob"); #if OPTO_DU_ITERATOR_ASSERT // Record that a change happened here. - debug_only(_last_del = _out[i]; ++_del_tick); + DEBUG_ONLY(_last_del = _out[i]; ++_del_tick); #endif _out[i] = _out[--_outcnt]; // Smash the old edge so it can't be used accidentally. - debug_only(_out[_outcnt] = (Node *)(uintptr_t)0xdeadbeef); + DEBUG_ONLY(_out[_outcnt] = (Node *)(uintptr_t)0xdeadbeef); } #ifdef ASSERT @@ -533,10 +533,10 @@ class Node { } while (*--outp != n); *outp = _out[--_outcnt]; // Smash the old edge so it can't be used accidentally. - debug_only(_out[_outcnt] = (Node *)(uintptr_t)0xdeadbeef); + DEBUG_ONLY(_out[_outcnt] = (Node *)(uintptr_t)0xdeadbeef); // Record that a change happened here. #if OPTO_DU_ITERATOR_ASSERT - debug_only(_last_del = n; ++_del_tick); + DEBUG_ONLY(_last_del = n; ++_del_tick); #endif } // Close gap after removing edge. @@ -593,7 +593,7 @@ class Node { } // Swap input edge order. (Edge indexes i1 and i2 are usually 1 and 2.) void swap_edges(uint i1, uint i2) { - debug_only(uint check_hash = (VerifyHashTableKeys && _hash_lock) ? hash() : NO_HASH); + DEBUG_ONLY(uint check_hash = (VerifyHashTableKeys && _hash_lock) ? hash() : NO_HASH); // Def-Use info is unchanged Node* n1 = in(i1); Node* n2 = in(i2); @@ -1431,15 +1431,15 @@ class DUIterator : public DUIterator_Common { #endif DUIterator(const Node* node, int dummy_to_avoid_conversion) - { _idx = 0; debug_only(sample(node)); } + { _idx = 0; DEBUG_ONLY(sample(node)); } public: // initialize to garbage; clear _vdui to disable asserts DUIterator() - { /*initialize to garbage*/ debug_only(_vdui = false); } + { /*initialize to garbage*/ DEBUG_ONLY(_vdui = false); } DUIterator(const DUIterator& that) - { _idx = that._idx; debug_only(_vdui = false; reset(that)); } + { _idx = that._idx; DEBUG_ONLY(_vdui = false; reset(that)); } void operator++(int dummy_to_specify_postfix_op) { _idx++; VDUI_ONLY(verify_increment()); } @@ -1451,7 +1451,7 @@ class DUIterator : public DUIterator_Common { { VDUI_ONLY(verify_finish()); } void operator=(const DUIterator& that) - { _idx = that._idx; debug_only(reset(that)); } + { _idx = that._idx; DEBUG_ONLY(reset(that)); } }; DUIterator Node::outs() const @@ -1461,7 +1461,7 @@ DUIterator& Node::refresh_out_pos(DUIterator& i) const bool Node::has_out(DUIterator& i) const { I_VDUI_ONLY(i, i.verify(this,true));return i._idx < _outcnt; } Node* Node::out(DUIterator& i) const - { I_VDUI_ONLY(i, i.verify(this)); return debug_only(i._last=) _out[i._idx]; } + { I_VDUI_ONLY(i, i.verify(this)); return DEBUG_ONLY(i._last=) _out[i._idx]; } // Faster DU iterator. Disallows insertions into the out array. @@ -1496,15 +1496,15 @@ class DUIterator_Fast : public DUIterator_Common { // Note: offset must be signed, since -1 is sometimes passed DUIterator_Fast(const Node* node, ptrdiff_t offset) - { _outp = node->_out + offset; debug_only(sample(node)); } + { _outp = node->_out + offset; DEBUG_ONLY(sample(node)); } public: // initialize to garbage; clear _vdui to disable asserts DUIterator_Fast() - { /*initialize to garbage*/ debug_only(_vdui = false); } + { /*initialize to garbage*/ DEBUG_ONLY(_vdui = false); } DUIterator_Fast(const DUIterator_Fast& that) - { _outp = that._outp; debug_only(_vdui = false; reset(that)); } + { _outp = that._outp; DEBUG_ONLY(_vdui = false; reset(that)); } void operator++(int dummy_to_specify_postfix_op) { _outp++; VDUI_ONLY(verify(_node, true)); } @@ -1522,7 +1522,7 @@ class DUIterator_Fast : public DUIterator_Common { } void operator=(const DUIterator_Fast& that) - { _outp = that._outp; debug_only(reset(that)); } + { _outp = that._outp; DEBUG_ONLY(reset(that)); } }; DUIterator_Fast Node::fast_outs(DUIterator_Fast& imax) const { @@ -1533,7 +1533,7 @@ DUIterator_Fast Node::fast_outs(DUIterator_Fast& imax) const { } Node* Node::fast_out(DUIterator_Fast& i) const { I_VDUI_ONLY(i, i.verify(this)); - return debug_only(i._last=) *i._outp; + return DEBUG_ONLY(i._last=) *i._outp; } @@ -1591,7 +1591,7 @@ DUIterator_Last Node::last_outs(DUIterator_Last& imin) const { } Node* Node::last_out(DUIterator_Last& i) const { I_VDUI_ONLY(i, i.verify(this)); - return debug_only(i._last=) *i._outp; + return DEBUG_ONLY(i._last=) *i._outp; } #endif //OPTO_DU_ITERATOR_ASSERT @@ -2035,7 +2035,7 @@ class TypeNode : public Node { public: void set_type(const Type* t) { assert(t != nullptr, "sanity"); - debug_only(uint check_hash = (VerifyHashTableKeys && _hash_lock) ? hash() : NO_HASH); + DEBUG_ONLY(uint check_hash = (VerifyHashTableKeys && _hash_lock) ? hash() : NO_HASH); *(const Type**)&_type = t; // cast away const-ness // If this node is in the hash table, make sure it doesn't need a rehash. assert(check_hash == NO_HASH || check_hash == hash(), "type change must preserve hash code"); diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 9fe5ad562b0..1cd6ebabc4b 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -2971,7 +2971,7 @@ void Scheduling::anti_do_def( Block *b, Node *def, OptoReg::Name def_reg, int is } Node *kill = def; // Rename 'def' to more descriptive 'kill' - debug_only( def = (Node*)((intptr_t)0xdeadbeef); ) + DEBUG_ONLY( def = (Node*)((intptr_t)0xdeadbeef); ) // After some number of kills there _may_ be a later def Node *later_def = nullptr; diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index f7330d10df3..6fa0b0f497d 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -1835,10 +1835,10 @@ void Parse::merge_common(Parse::Block* target, int pnum) { // Now _gvn will join that with the meet of current inputs. // BOTTOM is never permissible here, 'cause pessimistically // Phis of pointers cannot lose the basic pointer type. - debug_only(const Type* bt1 = phi->bottom_type()); + DEBUG_ONLY(const Type* bt1 = phi->bottom_type()); assert(bt1 != Type::BOTTOM, "should not be building conflict phis"); map()->set_req(j, _gvn.transform(phi)); - debug_only(const Type* bt2 = phi->bottom_type()); + DEBUG_ONLY(const Type* bt2 = phi->bottom_type()); assert(bt2->higher_equal_speculative(bt1), "must be consistent with type-flow"); record_for_igvn(phi); } @@ -1936,7 +1936,7 @@ void Parse::ensure_phis_everywhere() { // Ensure a phi on all currently known memories. for (MergeMemStream mms(merged_memory()); mms.next_non_empty(); ) { ensure_memory_phi(mms.alias_idx()); - debug_only(mms.set_memory()); // keep the iterator happy + DEBUG_ONLY(mms.set_memory()); // keep the iterator happy } // Note: This is our only chance to create phis for memory slices. diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 9be15b153b3..82e5b3f9d85 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -123,7 +123,7 @@ Node *NodeHash::hash_find_insert( Node *n ) { if( !k ) { // ?Miss? NOT_PRODUCT( _lookup_misses++ ); _table[key] = n; // Insert into table! - debug_only(n->enter_hash_lock()); // Lock down the node while in the table. + DEBUG_ONLY(n->enter_hash_lock()); // Lock down the node while in the table. check_grow(); // Grow table if insert hit limit return nullptr; // Miss! } @@ -152,7 +152,7 @@ Node *NodeHash::hash_find_insert( Node *n ) { NOT_PRODUCT( _lookup_misses++ ); key = (first_sentinel == 0) ? key : first_sentinel; // ?saw sentinel? _table[key] = n; // Insert into table! - debug_only(n->enter_hash_lock()); // Lock down the node while in the table. + DEBUG_ONLY(n->enter_hash_lock()); // Lock down the node while in the table. check_grow(); // Grow table if insert hit limit return nullptr; // Miss! } @@ -188,7 +188,7 @@ void NodeHash::hash_insert( Node *n ) { key = (key + stride) & (_max-1); // Stride through table w/ relative prime } _table[key] = n; // Insert into table! - debug_only(n->enter_hash_lock()); // Lock down the node while in the table. + DEBUG_ONLY(n->enter_hash_lock()); // Lock down the node while in the table. // if( conflict ) { n->dump(); } } @@ -203,9 +203,9 @@ bool NodeHash::hash_delete( const Node *n ) { } uint key = hash & (_max-1); uint stride = key | 0x01; - debug_only( uint counter = 0; ); + DEBUG_ONLY( uint counter = 0; ); for( ; /* (k != nullptr) && (k != _sentinel) */; ) { - debug_only( counter++ ); + DEBUG_ONLY( counter++ ); NOT_PRODUCT( _delete_probes++ ); k = _table[key]; // Get hashed value if( !k ) { // Miss? @@ -215,7 +215,7 @@ bool NodeHash::hash_delete( const Node *n ) { else if( n == k ) { NOT_PRODUCT( _delete_hits++ ); _table[key] = _sentinel; // Hit! Label as deleted entry - debug_only(((Node*)n)->exit_hash_lock()); // Unlock the node upon removal from table. + DEBUG_ONLY(((Node*)n)->exit_hash_lock()); // Unlock the node upon removal from table. return true; } else { @@ -257,7 +257,7 @@ void NodeHash::grow() { for( uint i = 0; i < old_max; i++ ) { Node *m = *old_table++; if( !m || m == _sentinel ) continue; - debug_only(m->exit_hash_lock()); // Unlock the node upon removal from old table. + DEBUG_ONLY(m->exit_hash_lock()); // Unlock the node upon removal from old table. hash_insert(m); } } @@ -289,7 +289,7 @@ void NodeHash::remove_useless_nodes(VectorSet &useful) { for( uint i = 0; i < max; ++i ) { Node *n = at(i); if(n != nullptr && n != sentinel_node && !useful.test(n->_idx)) { - debug_only(n->exit_hash_lock()); // Unlock the node when removed + DEBUG_ONLY(n->exit_hash_lock()); // Unlock the node when removed _table[i] = sentinel_node; // Replace with placeholder } } diff --git a/src/hotspot/share/opto/regalloc.hpp b/src/hotspot/share/opto/regalloc.hpp index 86877e18325..c724406a168 100644 --- a/src/hotspot/share/opto/regalloc.hpp +++ b/src/hotspot/share/opto/regalloc.hpp @@ -60,12 +60,12 @@ class PhaseRegAlloc : public Phase { // Get the register associated with the Node OptoReg::Name get_reg_first( const Node *n ) const { - debug_only( if( n->_idx >= _node_regs_max_index ) n->dump(); ); + DEBUG_ONLY( if( n->_idx >= _node_regs_max_index ) n->dump(); ); assert( n->_idx < _node_regs_max_index, "Exceeded _node_regs array"); return _node_regs[n->_idx].first(); } OptoReg::Name get_reg_second( const Node *n ) const { - debug_only( if( n->_idx >= _node_regs_max_index ) n->dump(); ); + DEBUG_ONLY( if( n->_idx >= _node_regs_max_index ) n->dump(); ); assert( n->_idx < _node_regs_max_index, "Exceeded _node_regs array"); return _node_regs[n->_idx].second(); } diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 6d24fb26cd2..fcb0ac38ace 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -1944,7 +1944,7 @@ address OptoRuntime::handle_exception_C(JavaThread* current) { #ifndef PRODUCT SharedRuntime::_find_handler_ctr++; // find exception handler #endif - debug_only(NoHandleMark __hm;) + DEBUG_ONLY(NoHandleMark __hm;) nmethod* nm = nullptr; address handler_address = nullptr; { diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 4556555acea..163f94ee959 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -756,7 +756,7 @@ void Type::Initialize(Compile* current) { // delete the current Type and return the existing Type. Otherwise stick the // current Type in the Type table. const Type *Type::hashcons(void) { - debug_only(base()); // Check the assertion in Type::base(). + DEBUG_ONLY(base()); // Check the assertion in Type::base(). // Look up the Type in the Type dictionary Dict *tdic = type_dict(); Type* old = (Type*)(tdic->Insert(this, this, false)); diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index d2916fad185..430d6997e77 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -215,7 +215,7 @@ intptr_t jfieldIDWorkaround::encode_klass_hash(Klass* k, int offset) { field_klass = super_klass; // super contains the field also super_klass = field_klass->super(); } - debug_only(NoSafepointVerifier nosafepoint;) + DEBUG_ONLY(NoSafepointVerifier nosafepoint;) uintptr_t klass_hash = field_klass->identity_hash(); return ((klass_hash & klass_mask) << klass_shift) | checked_mask_in_place; } else { @@ -235,7 +235,7 @@ bool jfieldIDWorkaround::klass_hash_ok(Klass* k, jfieldID id) { uintptr_t as_uint = (uintptr_t) id; intptr_t klass_hash = (as_uint >> klass_shift) & klass_mask; do { - debug_only(NoSafepointVerifier nosafepoint;) + DEBUG_ONLY(NoSafepointVerifier nosafepoint;) // Could use a non-blocking query for identity_hash here... if ((k->identity_hash() & klass_mask) == klass_hash) return true; @@ -410,7 +410,7 @@ JNI_ENTRY(jfieldID, jni_FromReflectedField(JNIEnv *env, jobject field)) int offset = InstanceKlass::cast(k1)->field_offset( slot ); JNIid* id = InstanceKlass::cast(k1)->jni_id_for(offset); assert(id != nullptr, "corrupt Field object"); - debug_only(id->set_is_static_field_id();) + DEBUG_ONLY(id->set_is_static_field_id();) // A jfieldID for a static field is a JNIid specifying the field holder and the offset within the Klass* ret = jfieldIDWorkaround::to_static_jfieldID(id); return ret; @@ -472,7 +472,7 @@ JNI_ENTRY(jclass, jni_GetSuperclass(JNIEnv *env, jclass sub)) // return mirror for superclass Klass* super = k->java_super(); // super2 is the value computed by the compiler's getSuperClass intrinsic: - debug_only(Klass* super2 = ( k->is_array_klass() + DEBUG_ONLY(Klass* super2 = ( k->is_array_klass() ? vmClasses::Object_klass() : k->super() ) ); assert(super == super2, @@ -906,7 +906,7 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive selected_method = m; } else if (!m->has_itable_index()) { // non-interface call -- for that little speed boost, don't handlize - debug_only(NoSafepointVerifier nosafepoint;) + DEBUG_ONLY(NoSafepointVerifier nosafepoint;) // jni_GetMethodID makes sure class is linked and initialized // so m should have a valid vtable index. assert(m->valid_vtable_index(), "no valid vtable index"); @@ -1995,9 +1995,9 @@ JNI_ENTRY(jfieldID, jni_GetStaticFieldID(JNIEnv *env, jclass clazz, // A jfieldID for a static field is a JNIid specifying the field holder and the offset within the Klass* JNIid* id = fd.field_holder()->jni_id_for(fd.offset()); - debug_only(id->set_is_static_field_id();) + DEBUG_ONLY(id->set_is_static_field_id();) - debug_only(id->verify(fd.field_holder())); + DEBUG_ONLY(id->verify(fd.field_holder())); ret = jfieldIDWorkaround::to_static_jfieldID(id); return ret; diff --git a/src/hotspot/share/prims/jniCheck.cpp b/src/hotspot/share/prims/jniCheck.cpp index aa158490eab..14d9c36c9fd 100644 --- a/src/hotspot/share/prims/jniCheck.cpp +++ b/src/hotspot/share/prims/jniCheck.cpp @@ -2320,7 +2320,7 @@ struct JNINativeInterface_* jni_functions_check() { // make sure the last pointer in the checked table is not null, indicating // an addition to the JNINativeInterface_ structure without initializing // it in the checked table. - debug_only(intptr_t *lastPtr = (intptr_t *)((char *)&checked_jni_NativeInterface + \ + DEBUG_ONLY(intptr_t *lastPtr = (intptr_t *)((char *)&checked_jni_NativeInterface + \ sizeof(*unchecked_jni_NativeInterface) - sizeof(char *));) assert(*lastPtr != 0, "Mismatched JNINativeInterface tables, check for new entries"); diff --git a/src/hotspot/share/prims/jvmtiEnter.xsl b/src/hotspot/share/prims/jvmtiEnter.xsl index bbca1ccc6e1..d1274158be4 100644 --- a/src/hotspot/share/prims/jvmtiEnter.xsl +++ b/src/hotspot/share/prims/jvmtiEnter.xsl @@ -444,7 +444,7 @@ struct jvmtiInterface_1_ jvmti , current_thread) - debug_only(VMNativeEntryWrapper __vew;) + DEBUG_ONLY(VMNativeEntryWrapper __vew;) PreserveExceptionMark __em(this_thread); diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 7a0c9a428c5..b2af12b08a6 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -199,7 +199,7 @@ JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) { MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current_thread)); ThreadInVMfromNative __tiv(current_thread); VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread) - debug_only(VMNativeEntryWrapper __vew;) + DEBUG_ONLY(VMNativeEntryWrapper __vew;) JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 32dd6fc13e7..13822f73f77 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -384,7 +384,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current_thread)); ThreadInVMfromNative __tiv(current_thread); VM_ENTRY_BASE(jvmtiEnv*, JvmtiExport::get_jvmti_interface, current_thread) - debug_only(VMNativeEntryWrapper __vew;) + DEBUG_ONLY(VMNativeEntryWrapper __vew;) JvmtiEnv *jvmti_env = JvmtiEnv::create_a_jvmti(version); *penv = jvmti_env->jvmti_external(); // actual type is jvmtiEnv* -- not to be confused with JvmtiEnv* diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index e9d496fc696..b4119825bd3 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -102,7 +102,7 @@ JvmtiThreadState::JvmtiThreadState(JavaThread* thread, oop thread_oop) { // The thread state list manipulation code must not have safepoints. // See periodic_clean_up(). - debug_only(NoSafepointVerifier nosafepoint;) + DEBUG_ONLY(NoSafepointVerifier nosafepoint;) _prev = nullptr; _next = _head; @@ -154,7 +154,7 @@ JvmtiThreadState::~JvmtiThreadState() { { // The thread state list manipulation code must not have safepoints. // See periodic_clean_up(). - debug_only(NoSafepointVerifier nosafepoint;) + DEBUG_ONLY(NoSafepointVerifier nosafepoint;) if (_prev == nullptr) { assert(_head == this, "sanity check"); @@ -759,7 +759,7 @@ void JvmtiThreadState::add_env(JvmtiEnvBase *env) { // add this environment thread state to the end of the list (order is important) { // list deallocation (which occurs at a safepoint) cannot occur simultaneously - debug_only(NoSafepointVerifier nosafepoint;) + DEBUG_ONLY(NoSafepointVerifier nosafepoint;) JvmtiEnvThreadStateIterator it(this); JvmtiEnvThreadState* previous_ets = nullptr; diff --git a/src/hotspot/share/prims/perf.cpp b/src/hotspot/share/prims/perf.cpp index f5f91e4614f..0b051bbc60f 100644 --- a/src/hotspot/share/prims/perf.cpp +++ b/src/hotspot/share/prims/perf.cpp @@ -111,7 +111,7 @@ PERF_ENTRY(jobject, Perf_CreateLong(JNIEnv *env, jobject perf, jstring name, char* name_utf = nullptr; if (units <= 0 || units > PerfData::U_Last) { - debug_only(warning("unexpected units argument, units = %d", units)); + DEBUG_ONLY(warning("unexpected units argument, units = %d", units)); THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } @@ -150,7 +150,7 @@ PERF_ENTRY(jobject, Perf_CreateLong(JNIEnv *env, jobject perf, jstring name, break; default: /* Illegal Argument */ - debug_only(warning("unexpected variability value: %d", variability)); + DEBUG_ONLY(warning("unexpected variability value: %d", variability)); THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); break; } @@ -179,14 +179,14 @@ PERF_ENTRY(jobject, Perf_CreateByteArray(JNIEnv *env, jobject perf, // check for valid variability classification if (variability != PerfData::V_Constant && variability != PerfData::V_Variable) { - debug_only(warning("unexpected variability value: %d", variability)); + DEBUG_ONLY(warning("unexpected variability value: %d", variability)); THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } // check for valid units if (units != PerfData::U_String) { // only String based ByteArray objects are currently supported - debug_only(warning("unexpected units value: %d", variability)); + DEBUG_ONLY(warning("unexpected units value: %d", variability)); THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } diff --git a/src/hotspot/share/prims/upcallLinker.cpp b/src/hotspot/share/prims/upcallLinker.cpp index 911f0f3ad2c..bc6a56dab05 100644 --- a/src/hotspot/share/prims/upcallLinker.cpp +++ b/src/hotspot/share/prims/upcallLinker.cpp @@ -104,7 +104,7 @@ JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context) { context->jfa.copy(thread->frame_anchor()); thread->frame_anchor()->clear(); - debug_only(thread->inc_java_call_counter()); + DEBUG_ONLY(thread->inc_java_call_counter()); thread->set_active_handles(context->new_handles); // install new handle block and reset Java frame linkage return thread; @@ -118,7 +118,7 @@ void UpcallLinker::on_exit(UpcallStub::FrameData* context) { // restore previous handle block thread->set_active_handles(context->old_handles); - debug_only(thread->dec_java_call_counter()); + DEBUG_ONLY(thread->dec_java_call_counter()); thread->frame_anchor()->copy(&context->jfa); diff --git a/src/hotspot/share/runtime/handles.cpp b/src/hotspot/share/runtime/handles.cpp index f747b4dc76e..cd3bd3eb3e0 100644 --- a/src/hotspot/share/runtime/handles.cpp +++ b/src/hotspot/share/runtime/handles.cpp @@ -133,7 +133,7 @@ void HandleMark::initialize(Thread* thread) { _hwm = _area->_hwm; _max = _area->_max; _size_in_bytes = _area->_size_in_bytes; - debug_only(_area->_handle_mark_nesting++); + DEBUG_ONLY(_area->_handle_mark_nesting++); assert(_area->_handle_mark_nesting > 0, "must stack allocate HandleMarks"); // Link this in the thread diff --git a/src/hotspot/share/runtime/handles.hpp b/src/hotspot/share/runtime/handles.hpp index 8ed16d33a2f..d2020e34121 100644 --- a/src/hotspot/share/runtime/handles.hpp +++ b/src/hotspot/share/runtime/handles.hpp @@ -188,8 +188,8 @@ class HandleArea: public Arena { public: // Constructor HandleArea(MemTag mem_tag, HandleArea* prev) : Arena(mem_tag, Tag::tag_ha, Chunk::tiny_size) { - debug_only(_handle_mark_nesting = 0); - debug_only(_no_handle_mark_nesting = 0); + DEBUG_ONLY(_handle_mark_nesting = 0); + DEBUG_ONLY(_no_handle_mark_nesting = 0); _prev = prev; } @@ -212,7 +212,7 @@ class HandleArea: public Arena { // Garbage collection support void oops_do(OopClosure* f); - debug_only(bool no_handle_mark_active() { return _no_handle_mark_nesting > 0; }) + DEBUG_ONLY(bool no_handle_mark_active() { return _no_handle_mark_nesting > 0; }) }; diff --git a/src/hotspot/share/runtime/handles.inline.hpp b/src/hotspot/share/runtime/handles.inline.hpp index 669a940eca9..4d3dd527c0d 100644 --- a/src/hotspot/share/runtime/handles.inline.hpp +++ b/src/hotspot/share/runtime/handles.inline.hpp @@ -80,7 +80,7 @@ inline void HandleMark::push() { // This is intentionally a NOP. pop_and_restore will reset // values to the HandleMark further down the stack, typically // in JavaCalls::call_helper. - debug_only(_area->_handle_mark_nesting++); + DEBUG_ONLY(_area->_handle_mark_nesting++); } inline void HandleMark::pop_and_restore() { @@ -95,7 +95,7 @@ inline void HandleMark::pop_and_restore() { _area->_chunk = _chunk; _area->_hwm = _hwm; _area->_max = _max; - debug_only(_area->_handle_mark_nesting--); + DEBUG_ONLY(_area->_handle_mark_nesting--); } inline HandleMarkCleaner::HandleMarkCleaner(Thread* thread) { diff --git a/src/hotspot/share/runtime/interfaceSupport.inline.hpp b/src/hotspot/share/runtime/interfaceSupport.inline.hpp index 403ff1d9ea2..c52c2664faa 100644 --- a/src/hotspot/share/runtime/interfaceSupport.inline.hpp +++ b/src/hotspot/share/runtime/interfaceSupport.inline.hpp @@ -259,12 +259,12 @@ class VMNativeEntryWrapper { // in the codecache. #define VM_LEAF_BASE(result_type, header) \ - debug_only(NoHandleMark __hm;) \ + DEBUG_ONLY(NoHandleMark __hm;) \ os::verify_stack_alignment(); \ /* begin of body */ #define VM_ENTRY_BASE_FROM_LEAF(result_type, header, thread) \ - debug_only(ResetNoHandleMark __rnhm;) \ + DEBUG_ONLY(ResetNoHandleMark __rnhm;) \ HandleMarkCleaner __hm(thread); \ JavaThread* THREAD = thread; /* For exception macros. */ \ os::verify_stack_alignment(); \ @@ -286,7 +286,7 @@ class VMNativeEntryWrapper { MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current)); \ ThreadInVMfromJava __tiv(current); \ VM_ENTRY_BASE(result_type, header, current) \ - debug_only(VMEntryWrapper __vew;) + DEBUG_ONLY(VMEntryWrapper __vew;) // JRT_LEAF currently can be called from either _thread_in_Java or // _thread_in_native mode. @@ -305,7 +305,7 @@ class VMNativeEntryWrapper { #define JRT_LEAF(result_type, header) \ result_type header { \ VM_LEAF_BASE(result_type, header) \ - debug_only(NoSafepointVerifier __nsv;) + DEBUG_ONLY(NoSafepointVerifier __nsv;) #define JRT_ENTRY_NO_ASYNC(result_type, header) \ @@ -314,7 +314,7 @@ class VMNativeEntryWrapper { MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current)); \ ThreadInVMfromJava __tiv(current, false /* check asyncs */); \ VM_ENTRY_BASE(result_type, header, current) \ - debug_only(VMEntryWrapper __vew;) + DEBUG_ONLY(VMEntryWrapper __vew;) // Same as JRT Entry but allows for return value after the safepoint // to get back into Java from the VM @@ -329,14 +329,14 @@ class VMNativeEntryWrapper { assert(current == JavaThread::current(), "Must be"); \ ThreadInVMfromJava __tiv(current); \ JavaThread* THREAD = current; /* For exception macros. */ \ - debug_only(VMEntryWrapper __vew;) + DEBUG_ONLY(VMEntryWrapper __vew;) #define JRT_BLOCK_NO_ASYNC \ { \ assert(current == JavaThread::current(), "Must be"); \ ThreadInVMfromJava __tiv(current, false /* check asyncs */); \ JavaThread* THREAD = current; /* For exception macros. */ \ - debug_only(VMEntryWrapper __vew;) + DEBUG_ONLY(VMEntryWrapper __vew;) #define JRT_BLOCK_END } @@ -360,7 +360,7 @@ extern "C" { \ assert(thread == Thread::current(), "JNIEnv is only valid in same thread"); \ MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, thread)); \ ThreadInVMfromNative __tiv(thread); \ - debug_only(VMNativeEntryWrapper __vew;) \ + DEBUG_ONLY(VMNativeEntryWrapper __vew;) \ VM_ENTRY_BASE(result_type, header, thread) @@ -385,7 +385,7 @@ extern "C" { \ JavaThread* thread=JavaThread::thread_from_jni_environment(env); \ MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, thread)); \ ThreadInVMfromNative __tiv(thread); \ - debug_only(VMNativeEntryWrapper __vew;) \ + DEBUG_ONLY(VMNativeEntryWrapper __vew;) \ VM_ENTRY_BASE(result_type, header, thread) @@ -395,7 +395,7 @@ extern "C" { \ JavaThread* thread = JavaThread::current(); \ MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, thread)); \ ThreadInVMfromNative __tiv(thread); \ - debug_only(VMNativeEntryWrapper __vew;) \ + DEBUG_ONLY(VMNativeEntryWrapper __vew;) \ VM_ENTRY_BASE(result_type, header, thread) diff --git a/src/hotspot/share/runtime/javaCalls.cpp b/src/hotspot/share/runtime/javaCalls.cpp index 012cea19bb0..04bd0871073 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -91,7 +91,7 @@ JavaCallWrapper::JavaCallWrapper(const methodHandle& callee_method, Handle recei _anchor.copy(_thread->frame_anchor()); _thread->frame_anchor()->clear(); - debug_only(_thread->inc_java_call_counter()); + DEBUG_ONLY(_thread->inc_java_call_counter()); _thread->set_active_handles(new_handles); // install new handle block and reset Java frame linkage MACOS_AARCH64_ONLY(_thread->enable_wx(WXExec)); @@ -109,7 +109,7 @@ JavaCallWrapper::~JavaCallWrapper() { _thread->frame_anchor()->zap(); - debug_only(_thread->dec_java_call_counter()); + DEBUG_ONLY(_thread->dec_java_call_counter()); // Old thread-local info. has been restored. We are not back in the VM. ThreadStateTransition::transition_from_java(_thread, _thread_in_vm); diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index e4f377a1217..8a6da52d762 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -553,7 +553,7 @@ void JavaThread::interrupt() { // All callers should have 'this' thread protected by a // ThreadsListHandle so that it cannot terminate and deallocate // itself. - debug_only(check_for_dangling_thread_pointer(this);) + DEBUG_ONLY(check_for_dangling_thread_pointer(this);) // For Windows _interrupt_event WINDOWS_ONLY(osthread()->set_interrupted(true);) @@ -569,7 +569,7 @@ void JavaThread::interrupt() { } bool JavaThread::is_interrupted(bool clear_interrupted) { - debug_only(check_for_dangling_thread_pointer(this);) + DEBUG_ONLY(check_for_dangling_thread_pointer(this);) if (_threadObj.peek() == nullptr) { // If there is no j.l.Thread then it is impossible to have diff --git a/src/hotspot/share/runtime/jfieldIDWorkaround.hpp b/src/hotspot/share/runtime/jfieldIDWorkaround.hpp index e44fb064813..68db2e36d45 100644 --- a/src/hotspot/share/runtime/jfieldIDWorkaround.hpp +++ b/src/hotspot/share/runtime/jfieldIDWorkaround.hpp @@ -157,7 +157,7 @@ class jfieldIDWorkaround: AllStatic { static jfieldID to_jfieldID(InstanceKlass* k, int offset, bool is_static) { if (is_static) { JNIid *id = k->jni_id_for(offset); - debug_only(id->set_is_static_field_id()); + DEBUG_ONLY(id->set_is_static_field_id()); return jfieldIDWorkaround::to_static_jfieldID(id); } else { return jfieldIDWorkaround::to_instance_jfieldID(k, offset); diff --git a/src/hotspot/share/runtime/jniHandles.cpp b/src/hotspot/share/runtime/jniHandles.cpp index b4fc32947dd..e7564467a81 100644 --- a/src/hotspot/share/runtime/jniHandles.cpp +++ b/src/hotspot/share/runtime/jniHandles.cpp @@ -342,9 +342,9 @@ JNIHandleBlock* JNIHandleBlock::allocate_block(JavaThread* thread, AllocFailType block->_next = nullptr; block->_pop_frame_link = nullptr; // _last, _free_list & _allocate_before_rebuild initialized in allocate_handle - debug_only(block->_last = nullptr); - debug_only(block->_free_list = nullptr); - debug_only(block->_allocate_before_rebuild = -1); + DEBUG_ONLY(block->_last = nullptr); + DEBUG_ONLY(block->_free_list = nullptr); + DEBUG_ONLY(block->_allocate_before_rebuild = -1); return block; } diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index a58be403827..496ad372c38 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -243,7 +243,7 @@ char* os::iso8601_time(jlong milliseconds_since_19700101, char* buffer, size_t b } OSReturn os::set_priority(Thread* thread, ThreadPriority p) { - debug_only(Thread::check_for_dangling_thread_pointer(thread);) + DEBUG_ONLY(Thread::check_for_dangling_thread_pointer(thread);) if ((p >= MinPriority && p <= MaxPriority) || (p == CriticalPriority && thread->is_ConcurrentGC_thread())) { diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index a42576b562d..183ecea03ca 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -92,7 +92,7 @@ Thread::Thread(MemTag mem_tag) { new HandleMark(this); // plain initialization - debug_only(_owned_locks = nullptr;) + DEBUG_ONLY(_owned_locks = nullptr;) NOT_PRODUCT(_skip_gcalot = false;) _jvmti_env_iteration_count = 0; set_allocated_bytes(0); @@ -379,7 +379,7 @@ bool Thread::is_JavaThread_protected_by_TLH(const JavaThread* target) { } void Thread::set_priority(Thread* thread, ThreadPriority priority) { - debug_only(check_for_dangling_thread_pointer(thread);) + DEBUG_ONLY(check_for_dangling_thread_pointer(thread);) // Can return an error! (void)os::set_priority(thread, priority); } @@ -488,7 +488,7 @@ void Thread::print_on(outputStream* st, bool print_extended_info) const { } ThreadsSMRSupport::print_info_on(this, st); st->print(" "); - debug_only(if (WizardMode) print_owned_locks_on(st);) + DEBUG_ONLY(if (WizardMode) print_owned_locks_on(st);) } void Thread::print() const { print_on(tty); } diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 7a2c8d52969..a042a390925 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -455,7 +455,7 @@ class AbstractDumpWriter : public CHeapObj { void AbstractDumpWriter::write_fast(const void* s, size_t len) { assert(!_in_dump_segment || (_sub_record_left >= len), "sub-record too large"); assert(buffer_size() - position() >= len, "Must fit"); - debug_only(_sub_record_left -= len); + DEBUG_ONLY(_sub_record_left -= len); memcpy(buffer() + position(), s, len); set_position(position() + len); } @@ -467,7 +467,7 @@ bool AbstractDumpWriter::can_write_fast(size_t len) { // write raw bytes void AbstractDumpWriter::write_raw(const void* s, size_t len) { assert(!_in_dump_segment || (_sub_record_left >= len), "sub-record too large"); - debug_only(_sub_record_left -= len); + DEBUG_ONLY(_sub_record_left -= len); // flush buffer to make room. while (len > buffer_size() - position()) { @@ -591,8 +591,8 @@ void AbstractDumpWriter::start_sub_record(u1 tag, u4 len) { return; } - debug_only(_sub_record_left = len); - debug_only(_sub_record_ended = false); + DEBUG_ONLY(_sub_record_left = len); + DEBUG_ONLY(_sub_record_ended = false); write_u1(tag); } @@ -601,7 +601,7 @@ void AbstractDumpWriter::end_sub_record() { assert(_in_dump_segment, "must be in dump segment"); assert(_sub_record_left == 0, "sub-record not written completely"); assert(!_sub_record_ended, "Must not have ended yet"); - debug_only(_sub_record_ended = true); + DEBUG_ONLY(_sub_record_ended = true); } // Supports I/O operations for a dump diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index 89ee69242c9..d320e17fafb 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -228,7 +228,7 @@ void ThreadService::current_thread_exiting(JavaThread* jt, bool daemon) { // FIXME: JVMTI should call this function Handle ThreadService::get_current_contended_monitor(JavaThread* thread) { assert(thread != nullptr, "should be non-null"); - debug_only(Thread::check_for_dangling_thread_pointer(thread);) + DEBUG_ONLY(Thread::check_for_dangling_thread_pointer(thread);) // This function can be called on a target JavaThread that is not // the caller and we are not at a safepoint. So it is possible for diff --git a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp index 31e797fc192..86b7ed5f917 100644 --- a/src/hotspot/share/utilities/growableArray.hpp +++ b/src/hotspot/share/utilities/growableArray.hpp @@ -622,7 +622,7 @@ class GrowableArrayMetadata { uintptr_t _bits; // resource area nesting at creation - debug_only(GrowableArrayNestingCheck _nesting_check;) + DEBUG_ONLY(GrowableArrayNestingCheck _nesting_check;) // Resource allocation static uintptr_t bits() { @@ -645,19 +645,19 @@ class GrowableArrayMetadata { // Resource allocation GrowableArrayMetadata() : _bits(bits()) - debug_only(COMMA _nesting_check(true)) { + DEBUG_ONLY(COMMA _nesting_check(true)) { } // Arena allocation GrowableArrayMetadata(Arena* arena) : _bits(bits(arena)) - debug_only(COMMA _nesting_check(arena)) { + DEBUG_ONLY(COMMA _nesting_check(arena)) { } // CHeap allocation GrowableArrayMetadata(MemTag mem_tag) : _bits(bits(mem_tag)) - debug_only(COMMA _nesting_check(false)) { + DEBUG_ONLY(COMMA _nesting_check(false)) { } #ifdef ASSERT @@ -725,7 +725,7 @@ class GrowableArray : public GrowableArrayWithAllocator> { GrowableArrayMetadata _metadata; - void init_checks() const { debug_only(_metadata.init_checks(this);) } + void init_checks() const { DEBUG_ONLY(_metadata.init_checks(this);) } // Where are we going to allocate memory? bool on_C_heap() const { return _metadata.on_C_heap(); } @@ -734,7 +734,7 @@ class GrowableArray : public GrowableArrayWithAllocator> { E* allocate() { if (on_resource_area()) { - debug_only(_metadata.on_resource_area_alloc_check()); + DEBUG_ONLY(_metadata.on_resource_area_alloc_check()); return allocate(this->_capacity); } @@ -743,7 +743,7 @@ class GrowableArray : public GrowableArrayWithAllocator> { } assert(on_arena(), "Sanity"); - debug_only(_metadata.on_arena_alloc_check()); + DEBUG_ONLY(_metadata.on_arena_alloc_check()); return allocate(this->_capacity, _metadata.arena()); } diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index 5c3cfaa0dd5..a5caf316aa3 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -377,13 +377,10 @@ #define DEBUG_ONLY(code) code #define NOT_DEBUG(code) #define NOT_DEBUG_RETURN /*next token must be ;*/ -// Historical. -#define debug_only(code) code #else // ASSERT #define DEBUG_ONLY(code) #define NOT_DEBUG(code) code #define NOT_DEBUG_RETURN {} -#define debug_only(code) #endif // ASSERT #ifdef _LP64 From 2447b9812a9f7316a2313f70db4974534fceb9d9 Mon Sep 17 00:00:00 2001 From: Suchismith Roy Date: Mon, 28 Apr 2025 08:44:36 +0000 Subject: [PATCH 054/118] 8355498: [AIX] Adapt code for C++ VLA rule Reviewed-by: jkern, mdoerr --- src/hotspot/os/aix/os_perf_aix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/os/aix/os_perf_aix.cpp b/src/hotspot/os/aix/os_perf_aix.cpp index e9feb3fe47d..8444002b871 100644 --- a/src/hotspot/os/aix/os_perf_aix.cpp +++ b/src/hotspot/os/aix/os_perf_aix.cpp @@ -72,7 +72,7 @@ enum { * Get info for requested PID from /proc//psinfo file */ static bool read_psinfo(const u_longlong_t& pid, psinfo_t& psinfo) { - static size_t BUF_LENGTH = 32 + sizeof(u_longlong_t); + const size_t BUF_LENGTH = 32 + sizeof(u_longlong_t); FILE* fp; char buf[BUF_LENGTH]; From b0c3485d6c911898b1ac07eccfe7d2b2668144cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 28 Apr 2025 10:04:20 +0000 Subject: [PATCH 055/118] 8348282: Add option for syntax highlighting in javadoc snippets Reviewed-by: liach, nbenalla, erikj --- make/Docs.gmk | 2 +- .../doclets/formats/html/HtmlDoclet.java | 6 + .../formats/html/HtmlDocletWriter.java | 1 + .../doclets/formats/html/HtmlOptions.java | 22 +- .../doclets/formats/html/markup/Head.java | 16 + .../formats/html/resources/highlight.css | 67 + .../formats/html/resources/highlight.js | 3278 +++++++++++++++++ .../formats/html/resources/script.js.template | 4 + .../html/resources/standard.properties | 4 + .../formats/html/resources/stylesheet.css | 17 +- .../doclets/toolkit/util/DocPaths.java | 8 +- src/jdk.javadoc/share/man/javadoc.md | 19 +- .../TestSyntaxHighlightOption.java | 97 + 13 files changed, 3527 insertions(+), 14 deletions(-) create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.js create mode 100644 test/langtools/jdk/javadoc/doclet/testSyntaxHighlightOption/TestSyntaxHighlightOption.java diff --git a/make/Docs.gmk b/make/Docs.gmk index 60c029ce8f9..965ae689e21 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -98,7 +98,7 @@ JAVADOC_DISABLED_DOCLINT_PACKAGES := org.w3c.* javax.smartcardio JAVADOC_OPTIONS := -use -keywords -notimestamp \ -serialwarn -encoding ISO-8859-1 -docencoding UTF-8 -breakiterator \ -splitIndex --system none -javafx --expand-requires transitive \ - --override-methods=summary + --override-methods=summary --syntax-highlight # The reference options must stay stable to allow for comparisons across the # development cycle. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java index b768aee081f..c6f583de361 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java @@ -311,6 +311,12 @@ protected void generateOtherFiles(ClassTree classTree) copyFontResources(); } + var syntaxHighlight = options.syntaxHighlight(); + if (syntaxHighlight) { + copyResource(DocPaths.HIGHLIGHT_CSS, DocPaths.RESOURCE_FILES.resolve(DocPaths.HIGHLIGHT_CSS), true); + copyResource(DocPaths.HIGHLIGHT_JS, DocPaths.SCRIPT_FILES.resolve(DocPaths.HIGHLIGHT_JS), true); + } + // If a stylesheet file is not specified, copy the default stylesheet // and replace newline with platform-specific newline. if (options.stylesheetFile().isEmpty()) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 448a68fd5a1..34ef40ed650 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -511,6 +511,7 @@ public void printHtmlDocument(List metakeywords, .setStylesheets(configuration.getMainStylesheet(), additionalStylesheets, localStylesheets) .setAdditionalScripts(configuration.getAdditionalScripts()) .setIndex(options.createIndex(), mainBodyScript) + .setSyntaxHighlight(options.syntaxHighlight()) .addContent(extraHeadContent); HtmlDocument htmlDocument = new HtmlDocument( diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlOptions.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlOptions.java index 10483fb4a4c..faf1f8c897d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlOptions.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -198,6 +198,11 @@ public class HtmlOptions extends BaseOptions { */ private String stylesheetFile = ""; + /** + * Argument for command line option {@code --syntax-highlight}. + */ + private boolean syntaxHighlight = false; + /** * Argument for command-line option {@code -tagletpath}. * The path to Taglets @@ -423,6 +428,14 @@ public boolean process(String opt, List args) { } }, + new Option(resources, "--syntax-highlight") { + @Override + public boolean process(String opt, List args) { + syntaxHighlight = true; + return true; + } + }, + new Option(resources, "-tag", 1) { @Override public boolean process(String opt, List args) { @@ -806,6 +819,13 @@ String stylesheetFile() { return stylesheetFile; } + /** + * Argument for command line option {@code --syntax-highlight}. + * True if command line option "--syntax-highlight" is used and syntax + * highlighting should be enabled. Default value is false. + */ + public boolean syntaxHighlight() { return syntaxHighlight; } + /** * Argument for command-line option {@code -tagletpath}. * The path to Taglets diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java index 7170c6bcc8a..0c54fc1e29c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java @@ -70,6 +70,7 @@ public class Head extends Content { private final List extraContent; private boolean addDefaultScript = true; private DocPath canonicalLink; + private boolean syntaxHighlight = false; /** * Creates a {@code Head} object, for a given file and HTML version. @@ -238,6 +239,16 @@ public void setCanonicalLink(DocPath link) { this.canonicalLink = link; } + /** + * Enables or disables support for syntax highlighting. + * @param value {@code true} to enable syntax highligting + * @return this object + */ + public Head setSyntaxHighlight(boolean value) { + this.syntaxHighlight = value; + return this; + } + /** * Adds additional content to be included in the HEAD element. * @@ -339,6 +350,11 @@ private void addStylesheets(HtmlTree head) { addStylesheet(head, DocPaths.RESOURCE_FILES.resolve(path)); } + if (syntaxHighlight) { + addStylesheet(head, DocPaths.RESOURCE_FILES.resolve(DocPaths.HIGHLIGHT_CSS)); + addScriptElement(head, DocPaths.HIGHLIGHT_JS); + } + for (DocPath path : localStylesheets) { // Local stylesheets are contained in doc-files, so omit resource-files prefix addStylesheet(head, path); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css new file mode 100644 index 00000000000..145c1c7f5d2 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.css @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ + */ +/* Syntax highlight style sheet */ +.hljs-title.function_, +.hljs-template-variable { + color: #00738F; +} +.hljs-code, +.hljs-comment, +.hljs-quote { + color: #6e6e71; + font-style: italic; +} +.hljs-meta { + color: #836F00; +} +.hljs-symbol, +.hljs-template-tag, +.hljs-keyword, +.hljs-literal, +.hljs-name, +.hljs-built_in, +.hljs-char.escape_ { + color: #0C40C2; +} +.hljs-variable, +.hljs-property, +.hljs-attr, +.hljs-section { + color: #841191; +} +.hljs-attribute { + color: #164ad9; +} +.hljs-regexp, +.hljs-number { + color: #104BEB; +} +.hljs-link { + color: #47688a; +} +.hljs-string { + color: #008313; +} +.hljs-doctag { + text-decoration: underline; +} +.hljs-emphasis { + font-style: italic; +} +.hljs-strong { + font-weight: bold; +} +.hljs-subst, +.hljs-title, +.hljs-params, +.hljs-bullet, +.hljs-formula, +.hljs-tag, +.hljs-type { + /* ignored */ +} + diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.js b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.js new file mode 100644 index 00000000000..efa14c8c306 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/highlight.js @@ -0,0 +1,3278 @@ +/*! + Highlight.js v11.11.1 (git: 08cb242e7d) + (c) 2006-2025 Josh Goebel and other contributors + License: BSD-3-Clause + */ +var hljs = (function () { + 'use strict'; + + /* eslint-disable no-multi-assign */ + + function deepFreeze(obj) { + if (obj instanceof Map) { + obj.clear = + obj.delete = + obj.set = + function () { + throw new Error('map is read-only'); + }; + } else if (obj instanceof Set) { + obj.add = + obj.clear = + obj.delete = + function () { + throw new Error('set is read-only'); + }; + } + + // Freeze self + Object.freeze(obj); + + Object.getOwnPropertyNames(obj).forEach((name) => { + const prop = obj[name]; + const type = typeof prop; + + // Freeze prop if it is an object or function and also not already frozen + if ((type === 'object' || type === 'function') && !Object.isFrozen(prop)) { + deepFreeze(prop); + } + }); + + return obj; + } + + /** @typedef {import('highlight.js').CallbackResponse} CallbackResponse */ + /** @typedef {import('highlight.js').CompiledMode} CompiledMode */ + /** @implements CallbackResponse */ + + class Response { + /** + * @param {CompiledMode} mode + */ + constructor(mode) { + // eslint-disable-next-line no-undefined + if (mode.data === undefined) mode.data = {}; + + this.data = mode.data; + this.isMatchIgnored = false; + } + + ignoreMatch() { + this.isMatchIgnored = true; + } + } + + /** + * @param {string} value + * @returns {string} + */ + function escapeHTML(value) { + return value + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + } + + /** + * performs a shallow merge of multiple objects into one + * + * @template T + * @param {T} original + * @param {Record[]} objects + * @returns {T} a single new object + */ + function inherit$1(original, ...objects) { + /** @type Record */ + const result = Object.create(null); + + for (const key in original) { + result[key] = original[key]; + } + objects.forEach(function(obj) { + for (const key in obj) { + result[key] = obj[key]; + } + }); + return /** @type {T} */ (result); + } + + /** + * @typedef {object} Renderer + * @property {(text: string) => void} addText + * @property {(node: Node) => void} openNode + * @property {(node: Node) => void} closeNode + * @property {() => string} value + */ + + /** @typedef {{scope?: string, language?: string, sublanguage?: boolean}} Node */ + /** @typedef {{walk: (r: Renderer) => void}} Tree */ + /** */ + + const SPAN_CLOSE = ''; + + /** + * Determines if a node needs to be wrapped in + * + * @param {Node} node */ + const emitsWrappingTags = (node) => { + // rarely we can have a sublanguage where language is undefined + // TODO: track down why + return !!node.scope; + }; + + /** + * + * @param {string} name + * @param {{prefix:string}} options + */ + const scopeToCSSClass = (name, { prefix }) => { + // sub-language + if (name.startsWith("language:")) { + return name.replace("language:", "language-"); + } + // tiered scope: comment.line + if (name.includes(".")) { + const pieces = name.split("."); + return [ + `${prefix}${pieces.shift()}`, + ...(pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`)) + ].join(" "); + } + // simple scope + return `${prefix}${name}`; + }; + + /** @type {Renderer} */ + class HTMLRenderer { + /** + * Creates a new HTMLRenderer + * + * @param {Tree} parseTree - the parse tree (must support `walk` API) + * @param {{classPrefix: string}} options + */ + constructor(parseTree, options) { + this.buffer = ""; + this.classPrefix = options.classPrefix; + parseTree.walk(this); + } + + /** + * Adds texts to the output stream + * + * @param {string} text */ + addText(text) { + this.buffer += escapeHTML(text); + } + + /** + * Adds a node open to the output stream (if needed) + * + * @param {Node} node */ + openNode(node) { + if (!emitsWrappingTags(node)) return; + + const className = scopeToCSSClass(node.scope, + { prefix: this.classPrefix }); + this.span(className); + } + + /** + * Adds a node close to the output stream (if needed) + * + * @param {Node} node */ + closeNode(node) { + if (!emitsWrappingTags(node)) return; + + this.buffer += SPAN_CLOSE; + } + + /** + * returns the accumulated buffer + */ + value() { + return this.buffer; + } + + // helpers + + /** + * Builds a span element + * + * @param {string} className */ + span(className) { + this.buffer += ``; + } + } + + /** @typedef {{scope?: string, language?: string, children: Node[]} | string} Node */ + /** @typedef {{scope?: string, language?: string, children: Node[]} } DataNode */ + /** @typedef {import('highlight.js').Emitter} Emitter */ + /** */ + + /** @returns {DataNode} */ + const newNode = (opts = {}) => { + /** @type DataNode */ + const result = { children: [] }; + Object.assign(result, opts); + return result; + }; + + class TokenTree { + constructor() { + /** @type DataNode */ + this.rootNode = newNode(); + this.stack = [this.rootNode]; + } + + get top() { + return this.stack[this.stack.length - 1]; + } + + get root() { return this.rootNode; } + + /** @param {Node} node */ + add(node) { + this.top.children.push(node); + } + + /** @param {string} scope */ + openNode(scope) { + /** @type Node */ + const node = newNode({ scope }); + this.add(node); + this.stack.push(node); + } + + closeNode() { + if (this.stack.length > 1) { + return this.stack.pop(); + } + // eslint-disable-next-line no-undefined + return undefined; + } + + closeAllNodes() { + while (this.closeNode()); + } + + toJSON() { + return JSON.stringify(this.rootNode, null, 4); + } + + /** + * @typedef { import("./html_renderer").Renderer } Renderer + * @param {Renderer} builder + */ + walk(builder) { + // this does not + return this.constructor._walk(builder, this.rootNode); + // this works + // return TokenTree._walk(builder, this.rootNode); + } + + /** + * @param {Renderer} builder + * @param {Node} node + */ + static _walk(builder, node) { + if (typeof node === "string") { + builder.addText(node); + } else if (node.children) { + builder.openNode(node); + node.children.forEach((child) => this._walk(builder, child)); + builder.closeNode(node); + } + return builder; + } + + /** + * @param {Node} node + */ + static _collapse(node) { + if (typeof node === "string") return; + if (!node.children) return; + + if (node.children.every(el => typeof el === "string")) { + // node.text = node.children.join(""); + // delete node.children; + node.children = [node.children.join("")]; + } else { + node.children.forEach((child) => { + TokenTree._collapse(child); + }); + } + } + } + + /** + Currently this is all private API, but this is the minimal API necessary + that an Emitter must implement to fully support the parser. + + Minimal interface: + + - addText(text) + - __addSublanguage(emitter, subLanguageName) + - startScope(scope) + - endScope() + - finalize() + - toHTML() + + */ + + /** + * @implements {Emitter} + */ + class TokenTreeEmitter extends TokenTree { + /** + * @param {*} options + */ + constructor(options) { + super(); + this.options = options; + } + + /** + * @param {string} text + */ + addText(text) { + if (text === "") { return; } + + this.add(text); + } + + /** @param {string} scope */ + startScope(scope) { + this.openNode(scope); + } + + endScope() { + this.closeNode(); + } + + /** + * @param {Emitter & {root: DataNode}} emitter + * @param {string} name + */ + __addSublanguage(emitter, name) { + /** @type DataNode */ + const node = emitter.root; + if (name) node.scope = `language:${name}`; + + this.add(node); + } + + toHTML() { + const renderer = new HTMLRenderer(this, this.options); + return renderer.value(); + } + + finalize() { + this.closeAllNodes(); + return true; + } + } + + /** + * @param {string} value + * @returns {RegExp} + * */ + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function source(re) { + if (!re) return null; + if (typeof re === "string") return re; + + return re.source; + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function lookahead(re) { + return concat('(?=', re, ')'); + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function anyNumberOfTimes(re) { + return concat('(?:', re, ')*'); + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function optional(re) { + return concat('(?:', re, ')?'); + } + + /** + * @param {...(RegExp | string) } args + * @returns {string} + */ + function concat(...args) { + const joined = args.map((x) => source(x)).join(""); + return joined; + } + + /** + * @param { Array } args + * @returns {object} + */ + function stripOptionsFromArgs(args) { + const opts = args[args.length - 1]; + + if (typeof opts === 'object' && opts.constructor === Object) { + args.splice(args.length - 1, 1); + return opts; + } else { + return {}; + } + } + + /** @typedef { {capture?: boolean} } RegexEitherOptions */ + + /** + * Any of the passed expresssions may match + * + * Creates a huge this | this | that | that match + * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args + * @returns {string} + */ + function either(...args) { + /** @type { object & {capture?: boolean} } */ + const opts = stripOptionsFromArgs(args); + const joined = '(' + + (opts.capture ? "" : "?:") + + args.map((x) => source(x)).join("|") + ")"; + return joined; + } + + /** + * @param {RegExp | string} re + * @returns {number} + */ + function countMatchGroups(re) { + return (new RegExp(re.toString() + '|')).exec('').length - 1; + } + + /** + * Does lexeme start with a regular expression match at the beginning + * @param {RegExp} re + * @param {string} lexeme + */ + function startsWith(re, lexeme) { + const match = re && re.exec(lexeme); + return match && match.index === 0; + } + + // BACKREF_RE matches an open parenthesis or backreference. To avoid + // an incorrect parse, it additionally matches the following: + // - [...] elements, where the meaning of parentheses and escapes change + // - other escape sequences, so we do not misparse escape sequences as + // interesting elements + // - non-matching or lookahead parentheses, which do not capture. These + // follow the '(' with a '?'. + const BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./; + + // **INTERNAL** Not intended for outside usage + // join logically computes regexps.join(separator), but fixes the + // backreferences so they continue to match. + // it also places each individual regular expression into it's own + // match group, keeping track of the sequencing of those match groups + // is currently an exercise for the caller. :-) + /** + * @param {(string | RegExp)[]} regexps + * @param {{joinWith: string}} opts + * @returns {string} + */ + function _rewriteBackreferences(regexps, { joinWith }) { + let numCaptures = 0; + + return regexps.map((regex) => { + numCaptures += 1; + const offset = numCaptures; + let re = source(regex); + let out = ''; + + while (re.length > 0) { + const match = BACKREF_RE.exec(re); + if (!match) { + out += re; + break; + } + out += re.substring(0, match.index); + re = re.substring(match.index + match[0].length); + if (match[0][0] === '\\' && match[1]) { + // Adjust the backreference. + out += '\\' + String(Number(match[1]) + offset); + } else { + out += match[0]; + if (match[0] === '(') { + numCaptures++; + } + } + } + return out; + }).map(re => `(${re})`).join(joinWith); + } + + /** @typedef {import('highlight.js').Mode} Mode */ + /** @typedef {import('highlight.js').ModeCallback} ModeCallback */ + + // Common regexps + const MATCH_NOTHING_RE = /\b\B/; + const IDENT_RE = '[a-zA-Z]\\w*'; + const UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*'; + const NUMBER_RE = '\\b\\d+(\\.\\d+)?'; + const C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float + const BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... + const RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; + + /** + * @param { Partial & {binary?: string | RegExp} } opts + */ + const SHEBANG = (opts = {}) => { + const beginShebang = /^#![ ]*\//; + if (opts.binary) { + opts.begin = concat( + beginShebang, + /.*\b/, + opts.binary, + /\b.*/); + } + return inherit$1({ + scope: 'meta', + begin: beginShebang, + end: /$/, + relevance: 0, + /** @type {ModeCallback} */ + "on:begin": (m, resp) => { + if (m.index !== 0) resp.ignoreMatch(); + } + }, opts); + }; + + // Common modes + const BACKSLASH_ESCAPE = { + begin: '\\\\[\\s\\S]', relevance: 0 + }; + const APOS_STRING_MODE = { + scope: 'string', + begin: '\'', + end: '\'', + illegal: '\\n', + contains: [BACKSLASH_ESCAPE] + }; + const QUOTE_STRING_MODE = { + scope: 'string', + begin: '"', + end: '"', + illegal: '\\n', + contains: [BACKSLASH_ESCAPE] + }; + const PHRASAL_WORDS_MODE = { + begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ + }; + /** + * Creates a comment mode + * + * @param {string | RegExp} begin + * @param {string | RegExp} end + * @param {Mode | {}} [modeOptions] + * @returns {Partial} + */ + const COMMENT = function(begin, end, modeOptions = {}) { + const mode = inherit$1( + { + scope: 'comment', + begin, + end, + contains: [] + }, + modeOptions + ); + mode.contains.push({ + scope: 'doctag', + // hack to avoid the space from being included. the space is necessary to + // match here to prevent the plain text rule below from gobbling up doctags + begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)', + end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/, + excludeBegin: true, + relevance: 0 + }); + const ENGLISH_WORD = either( + // list of common 1 and 2 letter words in English + "I", + "a", + "is", + "so", + "us", + "to", + "at", + "if", + "in", + "it", + "on", + // note: this is not an exhaustive list of contractions, just popular ones + /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc + /[A-Za-z]+[-][a-z]+/, // `no-way`, etc. + /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences + ); + // looking like plain text, more likely to be a comment + mode.contains.push( + { + // TODO: how to include ", (, ) without breaking grammars that use these for + // comment delimiters? + // begin: /[ ]+([()"]?([A-Za-z'-]{3,}|is|a|I|so|us|[tT][oO]|at|if|in|it|on)[.]?[()":]?([.][ ]|[ ]|\))){3}/ + // --- + + // this tries to find sequences of 3 english words in a row (without any + // "programming" type syntax) this gives us a strong signal that we've + // TRULY found a comment - vs perhaps scanning with the wrong language. + // It's possible to find something that LOOKS like the start of the + // comment - but then if there is no readable text - good chance it is a + // false match and not a comment. + // + // for a visual example please see: + // https://github.com/highlightjs/highlight.js/issues/2827 + + begin: concat( + /[ ]+/, // necessary to prevent us gobbling up doctags like /* @author Bob Mcgill */ + '(', + ENGLISH_WORD, + /[.]?[:]?([.][ ]|[ ])/, + '){3}') // look for 3 words in a row + } + ); + return mode; + }; + const C_LINE_COMMENT_MODE = COMMENT('//', '$'); + const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/'); + const HASH_COMMENT_MODE = COMMENT('#', '$'); + const NUMBER_MODE = { + scope: 'number', + begin: NUMBER_RE, + relevance: 0 + }; + const C_NUMBER_MODE = { + scope: 'number', + begin: C_NUMBER_RE, + relevance: 0 + }; + const BINARY_NUMBER_MODE = { + scope: 'number', + begin: BINARY_NUMBER_RE, + relevance: 0 + }; + const REGEXP_MODE = { + scope: "regexp", + begin: /\/(?=[^/\n]*\/)/, + end: /\/[gimuy]*/, + contains: [ + BACKSLASH_ESCAPE, + { + begin: /\[/, + end: /\]/, + relevance: 0, + contains: [BACKSLASH_ESCAPE] + } + ] + }; + const TITLE_MODE = { + scope: 'title', + begin: IDENT_RE, + relevance: 0 + }; + const UNDERSCORE_TITLE_MODE = { + scope: 'title', + begin: UNDERSCORE_IDENT_RE, + relevance: 0 + }; + const METHOD_GUARD = { + // excludes method names from keyword processing + begin: '\\.\\s*' + UNDERSCORE_IDENT_RE, + relevance: 0 + }; + + /** + * Adds end same as begin mechanics to a mode + * + * Your mode must include at least a single () match group as that first match + * group is what is used for comparison + * @param {Partial} mode + */ + const END_SAME_AS_BEGIN = function(mode) { + return Object.assign(mode, + { + /** @type {ModeCallback} */ + 'on:begin': (m, resp) => { resp.data._beginMatch = m[1]; }, + /** @type {ModeCallback} */ + 'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); } + }); + }; + + var MODES = /*#__PURE__*/Object.freeze({ + __proto__: null, + APOS_STRING_MODE: APOS_STRING_MODE, + BACKSLASH_ESCAPE: BACKSLASH_ESCAPE, + BINARY_NUMBER_MODE: BINARY_NUMBER_MODE, + BINARY_NUMBER_RE: BINARY_NUMBER_RE, + COMMENT: COMMENT, + C_BLOCK_COMMENT_MODE: C_BLOCK_COMMENT_MODE, + C_LINE_COMMENT_MODE: C_LINE_COMMENT_MODE, + C_NUMBER_MODE: C_NUMBER_MODE, + C_NUMBER_RE: C_NUMBER_RE, + END_SAME_AS_BEGIN: END_SAME_AS_BEGIN, + HASH_COMMENT_MODE: HASH_COMMENT_MODE, + IDENT_RE: IDENT_RE, + MATCH_NOTHING_RE: MATCH_NOTHING_RE, + METHOD_GUARD: METHOD_GUARD, + NUMBER_MODE: NUMBER_MODE, + NUMBER_RE: NUMBER_RE, + PHRASAL_WORDS_MODE: PHRASAL_WORDS_MODE, + QUOTE_STRING_MODE: QUOTE_STRING_MODE, + REGEXP_MODE: REGEXP_MODE, + RE_STARTERS_RE: RE_STARTERS_RE, + SHEBANG: SHEBANG, + TITLE_MODE: TITLE_MODE, + UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE, + UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE + }); + + /** + @typedef {import('highlight.js').CallbackResponse} CallbackResponse + @typedef {import('highlight.js').CompilerExt} CompilerExt + */ + + // Grammar extensions / plugins + // See: https://github.com/highlightjs/highlight.js/issues/2833 + + // Grammar extensions allow "syntactic sugar" to be added to the grammar modes + // without requiring any underlying changes to the compiler internals. + + // `compileMatch` being the perfect small example of now allowing a grammar + // author to write `match` when they desire to match a single expression rather + // than being forced to use `begin`. The extension then just moves `match` into + // `begin` when it runs. Ie, no features have been added, but we've just made + // the experience of writing (and reading grammars) a little bit nicer. + + // ------ + + // TODO: We need negative look-behind support to do this properly + /** + * Skip a match if it has a preceding dot + * + * This is used for `beginKeywords` to prevent matching expressions such as + * `bob.keyword.do()`. The mode compiler automatically wires this up as a + * special _internal_ 'on:begin' callback for modes with `beginKeywords` + * @param {RegExpMatchArray} match + * @param {CallbackResponse} response + */ + function skipIfHasPrecedingDot(match, response) { + const before = match.input[match.index - 1]; + if (before === ".") { + response.ignoreMatch(); + } + } + + /** + * + * @type {CompilerExt} + */ + function scopeClassName(mode, _parent) { + // eslint-disable-next-line no-undefined + if (mode.className !== undefined) { + mode.scope = mode.className; + delete mode.className; + } + } + + /** + * `beginKeywords` syntactic sugar + * @type {CompilerExt} + */ + function beginKeywords(mode, parent) { + if (!parent) return; + if (!mode.beginKeywords) return; + + // for languages with keywords that include non-word characters checking for + // a word boundary is not sufficient, so instead we check for a word boundary + // or whitespace - this does no harm in any case since our keyword engine + // doesn't allow spaces in keywords anyways and we still check for the boundary + // first + mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)'; + mode.__beforeBegin = skipIfHasPrecedingDot; + mode.keywords = mode.keywords || mode.beginKeywords; + delete mode.beginKeywords; + + // prevents double relevance, the keywords themselves provide + // relevance, the mode doesn't need to double it + // eslint-disable-next-line no-undefined + if (mode.relevance === undefined) mode.relevance = 0; + } + + /** + * Allow `illegal` to contain an array of illegal values + * @type {CompilerExt} + */ + function compileIllegal(mode, _parent) { + if (!Array.isArray(mode.illegal)) return; + + mode.illegal = either(...mode.illegal); + } + + /** + * `match` to match a single expression for readability + * @type {CompilerExt} + */ + function compileMatch(mode, _parent) { + if (!mode.match) return; + if (mode.begin || mode.end) throw new Error("begin & end are not supported with match"); + + mode.begin = mode.match; + delete mode.match; + } + + /** + * provides the default 1 relevance to all modes + * @type {CompilerExt} + */ + function compileRelevance(mode, _parent) { + // eslint-disable-next-line no-undefined + if (mode.relevance === undefined) mode.relevance = 1; + } + + // allow beforeMatch to act as a "qualifier" for the match + // the full match begin must be [beforeMatch][begin] + const beforeMatchExt = (mode, parent) => { + if (!mode.beforeMatch) return; + // starts conflicts with endsParent which we need to make sure the child + // rule is not matched multiple times + if (mode.starts) throw new Error("beforeMatch cannot be used with starts"); + + const originalMode = Object.assign({}, mode); + Object.keys(mode).forEach((key) => { delete mode[key]; }); + + mode.keywords = originalMode.keywords; + mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin)); + mode.starts = { + relevance: 0, + contains: [ + Object.assign(originalMode, { endsParent: true }) + ] + }; + mode.relevance = 0; + + delete originalMode.beforeMatch; + }; + + // keywords that should have no default relevance value + const COMMON_KEYWORDS = [ + 'of', + 'and', + 'for', + 'in', + 'not', + 'or', + 'if', + 'then', + 'parent', // common variable name + 'list', // common variable name + 'value' // common variable name + ]; + + const DEFAULT_KEYWORD_SCOPE = "keyword"; + + /** + * Given raw keywords from a language definition, compile them. + * + * @param {string | Record | Array} rawKeywords + * @param {boolean} caseInsensitive + */ + function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) { + /** @type {import("highlight.js/private").KeywordDict} */ + const compiledKeywords = Object.create(null); + + // input can be a string of keywords, an array of keywords, or a object with + // named keys representing scopeName (which can then point to a string or array) + if (typeof rawKeywords === 'string') { + compileList(scopeName, rawKeywords.split(" ")); + } else if (Array.isArray(rawKeywords)) { + compileList(scopeName, rawKeywords); + } else { + Object.keys(rawKeywords).forEach(function(scopeName) { + // collapse all our objects back into the parent object + Object.assign( + compiledKeywords, + compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName) + ); + }); + } + return compiledKeywords; + + // --- + + /** + * Compiles an individual list of keywords + * + * Ex: "for if when while|5" + * + * @param {string} scopeName + * @param {Array} keywordList + */ + function compileList(scopeName, keywordList) { + if (caseInsensitive) { + keywordList = keywordList.map(x => x.toLowerCase()); + } + keywordList.forEach(function(keyword) { + const pair = keyword.split('|'); + compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])]; + }); + } + } + + /** + * Returns the proper score for a given keyword + * + * Also takes into account comment keywords, which will be scored 0 UNLESS + * another score has been manually assigned. + * @param {string} keyword + * @param {string} [providedScore] + */ + function scoreForKeyword(keyword, providedScore) { + // manual scores always win over common keywords + // so you can force a score of 1 if you really insist + if (providedScore) { + return Number(providedScore); + } + + return commonKeyword(keyword) ? 0 : 1; + } + + /** + * Determines if a given keyword is common or not + * + * @param {string} keyword */ + function commonKeyword(keyword) { + return COMMON_KEYWORDS.includes(keyword.toLowerCase()); + } + + /* + + For the reasoning behind this please see: + https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419 + + */ + + /** + * @type {Record} + */ + const seenDeprecations = {}; + + /** + * @param {string} message + */ + const error = (message) => { + console.error(message); + }; + + /** + * @param {string} message + * @param {any} args + */ + const warn = (message, ...args) => { + console.log(`WARN: ${message}`, ...args); + }; + + /** + * @param {string} version + * @param {string} message + */ + const deprecated = (version, message) => { + if (seenDeprecations[`${version}/${message}`]) return; + + console.log(`Deprecated as of ${version}. ${message}`); + seenDeprecations[`${version}/${message}`] = true; + }; + + /* eslint-disable no-throw-literal */ + + /** + @typedef {import('highlight.js').CompiledMode} CompiledMode + */ + + const MultiClassError = new Error(); + + /** + * Renumbers labeled scope names to account for additional inner match + * groups that otherwise would break everything. + * + * Lets say we 3 match scopes: + * + * { 1 => ..., 2 => ..., 3 => ... } + * + * So what we need is a clean match like this: + * + * (a)(b)(c) => [ "a", "b", "c" ] + * + * But this falls apart with inner match groups: + * + * (a)(((b)))(c) => ["a", "b", "b", "b", "c" ] + * + * Our scopes are now "out of alignment" and we're repeating `b` 3 times. + * What needs to happen is the numbers are remapped: + * + * { 1 => ..., 2 => ..., 5 => ... } + * + * We also need to know that the ONLY groups that should be output + * are 1, 2, and 5. This function handles this behavior. + * + * @param {CompiledMode} mode + * @param {Array} regexes + * @param {{key: "beginScope"|"endScope"}} opts + */ + function remapScopeNames(mode, regexes, { key }) { + let offset = 0; + const scopeNames = mode[key]; + /** @type Record */ + const emit = {}; + /** @type Record */ + const positions = {}; + + for (let i = 1; i <= regexes.length; i++) { + positions[i + offset] = scopeNames[i]; + emit[i + offset] = true; + offset += countMatchGroups(regexes[i - 1]); + } + // we use _emit to keep track of which match groups are "top-level" to avoid double + // output from inside match groups + mode[key] = positions; + mode[key]._emit = emit; + mode[key]._multi = true; + } + + /** + * @param {CompiledMode} mode + */ + function beginMultiClass(mode) { + if (!Array.isArray(mode.begin)) return; + + if (mode.skip || mode.excludeBegin || mode.returnBegin) { + error("skip, excludeBegin, returnBegin not compatible with beginScope: {}"); + throw MultiClassError; + } + + if (typeof mode.beginScope !== "object" || mode.beginScope === null) { + error("beginScope must be object"); + throw MultiClassError; + } + + remapScopeNames(mode, mode.begin, { key: "beginScope" }); + mode.begin = _rewriteBackreferences(mode.begin, { joinWith: "" }); + } + + /** + * @param {CompiledMode} mode + */ + function endMultiClass(mode) { + if (!Array.isArray(mode.end)) return; + + if (mode.skip || mode.excludeEnd || mode.returnEnd) { + error("skip, excludeEnd, returnEnd not compatible with endScope: {}"); + throw MultiClassError; + } + + if (typeof mode.endScope !== "object" || mode.endScope === null) { + error("endScope must be object"); + throw MultiClassError; + } + + remapScopeNames(mode, mode.end, { key: "endScope" }); + mode.end = _rewriteBackreferences(mode.end, { joinWith: "" }); + } + + /** + * this exists only to allow `scope: {}` to be used beside `match:` + * Otherwise `beginScope` would necessary and that would look weird + + { + match: [ /def/, /\w+/ ] + scope: { 1: "keyword" , 2: "title" } + } + + * @param {CompiledMode} mode + */ + function scopeSugar(mode) { + if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) { + mode.beginScope = mode.scope; + delete mode.scope; + } + } + + /** + * @param {CompiledMode} mode + */ + function MultiClass(mode) { + scopeSugar(mode); + + if (typeof mode.beginScope === "string") { + mode.beginScope = { _wrap: mode.beginScope }; + } + if (typeof mode.endScope === "string") { + mode.endScope = { _wrap: mode.endScope }; + } + + beginMultiClass(mode); + endMultiClass(mode); + } + + /** + @typedef {import('highlight.js').Mode} Mode + @typedef {import('highlight.js').CompiledMode} CompiledMode + @typedef {import('highlight.js').Language} Language + @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin + @typedef {import('highlight.js').CompiledLanguage} CompiledLanguage + */ + + // compilation + + /** + * Compiles a language definition result + * + * Given the raw result of a language definition (Language), compiles this so + * that it is ready for highlighting code. + * @param {Language} language + * @returns {CompiledLanguage} + */ + function compileLanguage(language) { + /** + * Builds a regex with the case sensitivity of the current language + * + * @param {RegExp | string} value + * @param {boolean} [global] + */ + function langRe(value, global) { + return new RegExp( + source(value), + 'm' + + (language.case_insensitive ? 'i' : '') + + (language.unicodeRegex ? 'u' : '') + + (global ? 'g' : '') + ); + } + + /** + Stores multiple regular expressions and allows you to quickly search for + them all in a string simultaneously - returning the first match. It does + this by creating a huge (a|b|c) regex - each individual item wrapped with () + and joined by `|` - using match groups to track position. When a match is + found checking which position in the array has content allows us to figure + out which of the original regexes / match groups triggered the match. + + The match object itself (the result of `Regex.exec`) is returned but also + enhanced by merging in any meta-data that was registered with the regex. + This is how we keep track of which mode matched, and what type of rule + (`illegal`, `begin`, end, etc). + */ + class MultiRegex { + constructor() { + this.matchIndexes = {}; + // @ts-ignore + this.regexes = []; + this.matchAt = 1; + this.position = 0; + } + + // @ts-ignore + addRule(re, opts) { + opts.position = this.position++; + // @ts-ignore + this.matchIndexes[this.matchAt] = opts; + this.regexes.push([opts, re]); + this.matchAt += countMatchGroups(re) + 1; + } + + compile() { + if (this.regexes.length === 0) { + // avoids the need to check length every time exec is called + // @ts-ignore + this.exec = () => null; + } + const terminators = this.regexes.map(el => el[1]); + this.matcherRe = langRe(_rewriteBackreferences(terminators, { joinWith: '|' }), true); + this.lastIndex = 0; + } + + /** @param {string} s */ + exec(s) { + this.matcherRe.lastIndex = this.lastIndex; + const match = this.matcherRe.exec(s); + if (!match) { return null; } + + // eslint-disable-next-line no-undefined + const i = match.findIndex((el, i) => i > 0 && el !== undefined); + // @ts-ignore + const matchData = this.matchIndexes[i]; + // trim off any earlier non-relevant match groups (ie, the other regex + // match groups that make up the multi-matcher) + match.splice(0, i); + + return Object.assign(match, matchData); + } + } + + /* + Created to solve the key deficiently with MultiRegex - there is no way to + test for multiple matches at a single location. Why would we need to do + that? In the future a more dynamic engine will allow certain matches to be + ignored. An example: if we matched say the 3rd regex in a large group but + decided to ignore it - we'd need to started testing again at the 4th + regex... but MultiRegex itself gives us no real way to do that. + + So what this class creates MultiRegexs on the fly for whatever search + position they are needed. + + NOTE: These additional MultiRegex objects are created dynamically. For most + grammars most of the time we will never actually need anything more than the + first MultiRegex - so this shouldn't have too much overhead. + + Say this is our search group, and we match regex3, but wish to ignore it. + + regex1 | regex2 | regex3 | regex4 | regex5 ' ie, startAt = 0 + + What we need is a new MultiRegex that only includes the remaining + possibilities: + + regex4 | regex5 ' ie, startAt = 3 + + This class wraps all that complexity up in a simple API... `startAt` decides + where in the array of expressions to start doing the matching. It + auto-increments, so if a match is found at position 2, then startAt will be + set to 3. If the end is reached startAt will return to 0. + + MOST of the time the parser will be setting startAt manually to 0. + */ + class ResumableMultiRegex { + constructor() { + // @ts-ignore + this.rules = []; + // @ts-ignore + this.multiRegexes = []; + this.count = 0; + + this.lastIndex = 0; + this.regexIndex = 0; + } + + // @ts-ignore + getMatcher(index) { + if (this.multiRegexes[index]) return this.multiRegexes[index]; + + const matcher = new MultiRegex(); + this.rules.slice(index).forEach(([re, opts]) => matcher.addRule(re, opts)); + matcher.compile(); + this.multiRegexes[index] = matcher; + return matcher; + } + + resumingScanAtSamePosition() { + return this.regexIndex !== 0; + } + + considerAll() { + this.regexIndex = 0; + } + + // @ts-ignore + addRule(re, opts) { + this.rules.push([re, opts]); + if (opts.type === "begin") this.count++; + } + + /** @param {string} s */ + exec(s) { + const m = this.getMatcher(this.regexIndex); + m.lastIndex = this.lastIndex; + let result = m.exec(s); + + // The following is because we have no easy way to say "resume scanning at the + // existing position but also skip the current rule ONLY". What happens is + // all prior rules are also skipped which can result in matching the wrong + // thing. Example of matching "booger": + + // our matcher is [string, "booger", number] + // + // ....booger.... + + // if "booger" is ignored then we'd really need a regex to scan from the + // SAME position for only: [string, number] but ignoring "booger" (if it + // was the first match), a simple resume would scan ahead who knows how + // far looking only for "number", ignoring potential string matches (or + // future "booger" matches that might be valid.) + + // So what we do: We execute two matchers, one resuming at the same + // position, but the second full matcher starting at the position after: + + // /--- resume first regex match here (for [number]) + // |/---- full match here for [string, "booger", number] + // vv + // ....booger.... + + // Which ever results in a match first is then used. So this 3-4 step + // process essentially allows us to say "match at this position, excluding + // a prior rule that was ignored". + // + // 1. Match "booger" first, ignore. Also proves that [string] does non match. + // 2. Resume matching for [number] + // 3. Match at index + 1 for [string, "booger", number] + // 4. If #2 and #3 result in matches, which came first? + if (this.resumingScanAtSamePosition()) { + if (result && result.index === this.lastIndex) ; else { // use the second matcher result + const m2 = this.getMatcher(0); + m2.lastIndex = this.lastIndex + 1; + result = m2.exec(s); + } + } + + if (result) { + this.regexIndex += result.position + 1; + if (this.regexIndex === this.count) { + // wrap-around to considering all matches again + this.considerAll(); + } + } + + return result; + } + } + + /** + * Given a mode, builds a huge ResumableMultiRegex that can be used to walk + * the content and find matches. + * + * @param {CompiledMode} mode + * @returns {ResumableMultiRegex} + */ + function buildModeRegex(mode) { + const mm = new ResumableMultiRegex(); + + mode.contains.forEach(term => mm.addRule(term.begin, { rule: term, type: "begin" })); + + if (mode.terminatorEnd) { + mm.addRule(mode.terminatorEnd, { type: "end" }); + } + if (mode.illegal) { + mm.addRule(mode.illegal, { type: "illegal" }); + } + + return mm; + } + + /** skip vs abort vs ignore + * + * @skip - The mode is still entered and exited normally (and contains rules apply), + * but all content is held and added to the parent buffer rather than being + * output when the mode ends. Mostly used with `sublanguage` to build up + * a single large buffer than can be parsed by sublanguage. + * + * - The mode begin ands ends normally. + * - Content matched is added to the parent mode buffer. + * - The parser cursor is moved forward normally. + * + * @abort - A hack placeholder until we have ignore. Aborts the mode (as if it + * never matched) but DOES NOT continue to match subsequent `contains` + * modes. Abort is bad/suboptimal because it can result in modes + * farther down not getting applied because an earlier rule eats the + * content but then aborts. + * + * - The mode does not begin. + * - Content matched by `begin` is added to the mode buffer. + * - The parser cursor is moved forward accordingly. + * + * @ignore - Ignores the mode (as if it never matched) and continues to match any + * subsequent `contains` modes. Ignore isn't technically possible with + * the current parser implementation. + * + * - The mode does not begin. + * - Content matched by `begin` is ignored. + * - The parser cursor is not moved forward. + */ + + /** + * Compiles an individual mode + * + * This can raise an error if the mode contains certain detectable known logic + * issues. + * @param {Mode} mode + * @param {CompiledMode | null} [parent] + * @returns {CompiledMode | never} + */ + function compileMode(mode, parent) { + const cmode = /** @type CompiledMode */ (mode); + if (mode.isCompiled) return cmode; + + [ + scopeClassName, + // do this early so compiler extensions generally don't have to worry about + // the distinction between match/begin + compileMatch, + MultiClass, + beforeMatchExt + ].forEach(ext => ext(mode, parent)); + + language.compilerExtensions.forEach(ext => ext(mode, parent)); + + // __beforeBegin is considered private API, internal use only + mode.__beforeBegin = null; + + [ + beginKeywords, + // do this later so compiler extensions that come earlier have access to the + // raw array if they wanted to perhaps manipulate it, etc. + compileIllegal, + // default to 1 relevance if not specified + compileRelevance + ].forEach(ext => ext(mode, parent)); + + mode.isCompiled = true; + + let keywordPattern = null; + if (typeof mode.keywords === "object" && mode.keywords.$pattern) { + // we need a copy because keywords might be compiled multiple times + // so we can't go deleting $pattern from the original on the first + // pass + mode.keywords = Object.assign({}, mode.keywords); + keywordPattern = mode.keywords.$pattern; + delete mode.keywords.$pattern; + } + keywordPattern = keywordPattern || /\w+/; + + if (mode.keywords) { + mode.keywords = compileKeywords(mode.keywords, language.case_insensitive); + } + + cmode.keywordPatternRe = langRe(keywordPattern, true); + + if (parent) { + if (!mode.begin) mode.begin = /\B|\b/; + cmode.beginRe = langRe(cmode.begin); + if (!mode.end && !mode.endsWithParent) mode.end = /\B|\b/; + if (mode.end) cmode.endRe = langRe(cmode.end); + cmode.terminatorEnd = source(cmode.end) || ''; + if (mode.endsWithParent && parent.terminatorEnd) { + cmode.terminatorEnd += (mode.end ? '|' : '') + parent.terminatorEnd; + } + } + if (mode.illegal) cmode.illegalRe = langRe(/** @type {RegExp | string} */ (mode.illegal)); + if (!mode.contains) mode.contains = []; + + mode.contains = [].concat(...mode.contains.map(function(c) { + return expandOrCloneMode(c === 'self' ? mode : c); + })); + mode.contains.forEach(function(c) { compileMode(/** @type Mode */ (c), cmode); }); + + if (mode.starts) { + compileMode(mode.starts, parent); + } + + cmode.matcher = buildModeRegex(cmode); + return cmode; + } + + if (!language.compilerExtensions) language.compilerExtensions = []; + + // self is not valid at the top-level + if (language.contains && language.contains.includes('self')) { + throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation."); + } + + // we need a null object, which inherit will guarantee + language.classNameAliases = inherit$1(language.classNameAliases || {}); + + return compileMode(/** @type Mode */ (language)); + } + + /** + * Determines if a mode has a dependency on it's parent or not + * + * If a mode does have a parent dependency then often we need to clone it if + * it's used in multiple places so that each copy points to the correct parent, + * where-as modes without a parent can often safely be re-used at the bottom of + * a mode chain. + * + * @param {Mode | null} mode + * @returns {boolean} - is there a dependency on the parent? + * */ + function dependencyOnParent(mode) { + if (!mode) return false; + + return mode.endsWithParent || dependencyOnParent(mode.starts); + } + + /** + * Expands a mode or clones it if necessary + * + * This is necessary for modes with parental dependenceis (see notes on + * `dependencyOnParent`) and for nodes that have `variants` - which must then be + * exploded into their own individual modes at compile time. + * + * @param {Mode} mode + * @returns {Mode | Mode[]} + * */ + function expandOrCloneMode(mode) { + if (mode.variants && !mode.cachedVariants) { + mode.cachedVariants = mode.variants.map(function(variant) { + return inherit$1(mode, { variants: null }, variant); + }); + } + + // EXPAND + // if we have variants then essentially "replace" the mode with the variants + // this happens in compileMode, where this function is called from + if (mode.cachedVariants) { + return mode.cachedVariants; + } + + // CLONE + // if we have dependencies on parents then we need a unique + // instance of ourselves, so we can be reused with many + // different parents without issue + if (dependencyOnParent(mode)) { + return inherit$1(mode, { starts: mode.starts ? inherit$1(mode.starts) : null }); + } + + if (Object.isFrozen(mode)) { + return inherit$1(mode); + } + + // no special dependency issues, just return ourselves + return mode; + } + + var version = "11.11.1"; + + class HTMLInjectionError extends Error { + constructor(reason, html) { + super(reason); + this.name = "HTMLInjectionError"; + this.html = html; + } + } + + /* + Syntax highlighting with language autodetection. + https://highlightjs.org/ + */ + + + + /** + @typedef {import('highlight.js').Mode} Mode + @typedef {import('highlight.js').CompiledMode} CompiledMode + @typedef {import('highlight.js').CompiledScope} CompiledScope + @typedef {import('highlight.js').Language} Language + @typedef {import('highlight.js').HLJSApi} HLJSApi + @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin + @typedef {import('highlight.js').PluginEvent} PluginEvent + @typedef {import('highlight.js').HLJSOptions} HLJSOptions + @typedef {import('highlight.js').LanguageFn} LanguageFn + @typedef {import('highlight.js').HighlightedHTMLElement} HighlightedHTMLElement + @typedef {import('highlight.js').BeforeHighlightContext} BeforeHighlightContext + @typedef {import('highlight.js/private').MatchType} MatchType + @typedef {import('highlight.js/private').KeywordData} KeywordData + @typedef {import('highlight.js/private').EnhancedMatch} EnhancedMatch + @typedef {import('highlight.js/private').AnnotatedError} AnnotatedError + @typedef {import('highlight.js').AutoHighlightResult} AutoHighlightResult + @typedef {import('highlight.js').HighlightOptions} HighlightOptions + @typedef {import('highlight.js').HighlightResult} HighlightResult + */ + + + const escape = escapeHTML; + const inherit = inherit$1; + const NO_MATCH = Symbol("nomatch"); + const MAX_KEYWORD_HITS = 7; + + /** + * @param {any} hljs - object that is extended (legacy) + * @returns {HLJSApi} + */ + const HLJS = function(hljs) { + // Global internal variables used within the highlight.js library. + /** @type {Record} */ + const languages = Object.create(null); + /** @type {Record} */ + const aliases = Object.create(null); + /** @type {HLJSPlugin[]} */ + const plugins = []; + + // safe/production mode - swallows more errors, tries to keep running + // even if a single syntax or parse hits a fatal error + let SAFE_MODE = true; + const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a language module?"; + /** @type {Language} */ + const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] }; + + // Global options used when within external APIs. This is modified when + // calling the `hljs.configure` function. + /** @type HLJSOptions */ + let options = { + ignoreUnescapedHTML: false, + throwUnescapedHTML: false, + noHighlightRe: /^(no-?highlight)$/i, + languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i, + classPrefix: 'hljs-', + cssSelector: 'pre code', + languages: null, + // beta configuration options, subject to change, welcome to discuss + // https://github.com/highlightjs/highlight.js/issues/1086 + __emitter: TokenTreeEmitter + }; + + /* Utility functions */ + + /** + * Tests a language name to see if highlighting should be skipped + * @param {string} languageName + */ + function shouldNotHighlight(languageName) { + return options.noHighlightRe.test(languageName); + } + + /** + * @param {HighlightedHTMLElement} block - the HTML element to determine language for + */ + function blockLanguage(block) { + let classes = block.className + ' '; + + classes += block.parentNode ? block.parentNode.className : ''; + + // language-* takes precedence over non-prefixed class names. + const match = options.languageDetectRe.exec(classes); + if (match) { + const language = getLanguage(match[1]); + if (!language) { + warn(LANGUAGE_NOT_FOUND.replace("{}", match[1])); + warn("Falling back to no-highlight mode for this block.", block); + } + return language ? match[1] : 'no-highlight'; + } + + return classes + .split(/\s+/) + .find((_class) => shouldNotHighlight(_class) || getLanguage(_class)); + } + + /** + * Core highlighting function. + * + * OLD API + * highlight(lang, code, ignoreIllegals, continuation) + * + * NEW API + * highlight(code, {lang, ignoreIllegals}) + * + * @param {string} codeOrLanguageName - the language to use for highlighting + * @param {string | HighlightOptions} optionsOrCode - the code to highlight + * @param {boolean} [ignoreIllegals] - whether to ignore illegal matches, default is to bail + * + * @returns {HighlightResult} Result - an object that represents the result + * @property {string} language - the language name + * @property {number} relevance - the relevance score + * @property {string} value - the highlighted HTML code + * @property {string} code - the original raw code + * @property {CompiledMode} top - top of the current mode stack + * @property {boolean} illegal - indicates whether any illegal matches were found + */ + function highlight(codeOrLanguageName, optionsOrCode, ignoreIllegals) { + let code = ""; + let languageName = ""; + if (typeof optionsOrCode === "object") { + code = codeOrLanguageName; + ignoreIllegals = optionsOrCode.ignoreIllegals; + languageName = optionsOrCode.language; + } else { + // old API + deprecated("10.7.0", "highlight(lang, code, ...args) has been deprecated."); + deprecated("10.7.0", "Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"); + languageName = codeOrLanguageName; + code = optionsOrCode; + } + + // https://github.com/highlightjs/highlight.js/issues/3149 + // eslint-disable-next-line no-undefined + if (ignoreIllegals === undefined) { ignoreIllegals = true; } + + /** @type {BeforeHighlightContext} */ + const context = { + code, + language: languageName + }; + // the plugin can change the desired language or the code to be highlighted + // just be changing the object it was passed + fire("before:highlight", context); + + // a before plugin can usurp the result completely by providing it's own + // in which case we don't even need to call highlight + const result = context.result + ? context.result + : _highlight(context.language, context.code, ignoreIllegals); + + result.code = context.code; + // the plugin can change anything in result to suite it + fire("after:highlight", result); + + return result; + } + + /** + * private highlight that's used internally and does not fire callbacks + * + * @param {string} languageName - the language to use for highlighting + * @param {string} codeToHighlight - the code to highlight + * @param {boolean?} [ignoreIllegals] - whether to ignore illegal matches, default is to bail + * @param {CompiledMode?} [continuation] - current continuation mode, if any + * @returns {HighlightResult} - result of the highlight operation + */ + function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) { + const keywordHits = Object.create(null); + + /** + * Return keyword data if a match is a keyword + * @param {CompiledMode} mode - current mode + * @param {string} matchText - the textual match + * @returns {KeywordData | false} + */ + function keywordData(mode, matchText) { + return mode.keywords[matchText]; + } + + function processKeywords() { + if (!top.keywords) { + emitter.addText(modeBuffer); + return; + } + + let lastIndex = 0; + top.keywordPatternRe.lastIndex = 0; + let match = top.keywordPatternRe.exec(modeBuffer); + let buf = ""; + + while (match) { + buf += modeBuffer.substring(lastIndex, match.index); + const word = language.case_insensitive ? match[0].toLowerCase() : match[0]; + const data = keywordData(top, word); + if (data) { + const [kind, keywordRelevance] = data; + emitter.addText(buf); + buf = ""; + + keywordHits[word] = (keywordHits[word] || 0) + 1; + if (keywordHits[word] <= MAX_KEYWORD_HITS) relevance += keywordRelevance; + if (kind.startsWith("_")) { + // _ implied for relevance only, do not highlight + // by applying a class name + buf += match[0]; + } else { + const cssClass = language.classNameAliases[kind] || kind; + emitKeyword(match[0], cssClass); + } + } else { + buf += match[0]; + } + lastIndex = top.keywordPatternRe.lastIndex; + match = top.keywordPatternRe.exec(modeBuffer); + } + buf += modeBuffer.substring(lastIndex); + emitter.addText(buf); + } + + function processSubLanguage() { + if (modeBuffer === "") return; + /** @type HighlightResult */ + let result = null; + + if (typeof top.subLanguage === 'string') { + if (!languages[top.subLanguage]) { + emitter.addText(modeBuffer); + return; + } + result = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]); + continuations[top.subLanguage] = /** @type {CompiledMode} */ (result._top); + } else { + result = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null); + } + + // Counting embedded language score towards the host language may be disabled + // with zeroing the containing mode relevance. Use case in point is Markdown that + // allows XML everywhere and makes every XML snippet to have a much larger Markdown + // score. + if (top.relevance > 0) { + relevance += result.relevance; + } + emitter.__addSublanguage(result._emitter, result.language); + } + + function processBuffer() { + if (top.subLanguage != null) { + processSubLanguage(); + } else { + processKeywords(); + } + modeBuffer = ''; + } + + /** + * @param {string} text + * @param {string} scope + */ + function emitKeyword(keyword, scope) { + if (keyword === "") return; + + emitter.startScope(scope); + emitter.addText(keyword); + emitter.endScope(); + } + + /** + * @param {CompiledScope} scope + * @param {RegExpMatchArray} match + */ + function emitMultiClass(scope, match) { + let i = 1; + const max = match.length - 1; + while (i <= max) { + if (!scope._emit[i]) { i++; continue; } + const klass = language.classNameAliases[scope[i]] || scope[i]; + const text = match[i]; + if (klass) { + emitKeyword(text, klass); + } else { + modeBuffer = text; + processKeywords(); + modeBuffer = ""; + } + i++; + } + } + + /** + * @param {CompiledMode} mode - new mode to start + * @param {RegExpMatchArray} match + */ + function startNewMode(mode, match) { + if (mode.scope && typeof mode.scope === "string") { + emitter.openNode(language.classNameAliases[mode.scope] || mode.scope); + } + if (mode.beginScope) { + // beginScope just wraps the begin match itself in a scope + if (mode.beginScope._wrap) { + emitKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || mode.beginScope._wrap); + modeBuffer = ""; + } else if (mode.beginScope._multi) { + // at this point modeBuffer should just be the match + emitMultiClass(mode.beginScope, match); + modeBuffer = ""; + } + } + + top = Object.create(mode, { parent: { value: top } }); + return top; + } + + /** + * @param {CompiledMode } mode - the mode to potentially end + * @param {RegExpMatchArray} match - the latest match + * @param {string} matchPlusRemainder - match plus remainder of content + * @returns {CompiledMode | void} - the next mode, or if void continue on in current mode + */ + function endOfMode(mode, match, matchPlusRemainder) { + let matched = startsWith(mode.endRe, matchPlusRemainder); + + if (matched) { + if (mode["on:end"]) { + const resp = new Response(mode); + mode["on:end"](match, resp); + if (resp.isMatchIgnored) matched = false; + } + + if (matched) { + while (mode.endsParent && mode.parent) { + mode = mode.parent; + } + return mode; + } + } + // even if on:end fires an `ignore` it's still possible + // that we might trigger the end node because of a parent mode + if (mode.endsWithParent) { + return endOfMode(mode.parent, match, matchPlusRemainder); + } + } + + /** + * Handle matching but then ignoring a sequence of text + * + * @param {string} lexeme - string containing full match text + */ + function doIgnore(lexeme) { + if (top.matcher.regexIndex === 0) { + // no more regexes to potentially match here, so we move the cursor forward one + // space + modeBuffer += lexeme[0]; + return 1; + } else { + // no need to move the cursor, we still have additional regexes to try and + // match at this very spot + resumeScanAtSamePosition = true; + return 0; + } + } + + /** + * Handle the start of a new potential mode match + * + * @param {EnhancedMatch} match - the current match + * @returns {number} how far to advance the parse cursor + */ + function doBeginMatch(match) { + const lexeme = match[0]; + const newMode = match.rule; + + const resp = new Response(newMode); + // first internal before callbacks, then the public ones + const beforeCallbacks = [newMode.__beforeBegin, newMode["on:begin"]]; + for (const cb of beforeCallbacks) { + if (!cb) continue; + cb(match, resp); + if (resp.isMatchIgnored) return doIgnore(lexeme); + } + + if (newMode.skip) { + modeBuffer += lexeme; + } else { + if (newMode.excludeBegin) { + modeBuffer += lexeme; + } + processBuffer(); + if (!newMode.returnBegin && !newMode.excludeBegin) { + modeBuffer = lexeme; + } + } + startNewMode(newMode, match); + return newMode.returnBegin ? 0 : lexeme.length; + } + + /** + * Handle the potential end of mode + * + * @param {RegExpMatchArray} match - the current match + */ + function doEndMatch(match) { + const lexeme = match[0]; + const matchPlusRemainder = codeToHighlight.substring(match.index); + + const endMode = endOfMode(top, match, matchPlusRemainder); + if (!endMode) { return NO_MATCH; } + + const origin = top; + if (top.endScope && top.endScope._wrap) { + processBuffer(); + emitKeyword(lexeme, top.endScope._wrap); + } else if (top.endScope && top.endScope._multi) { + processBuffer(); + emitMultiClass(top.endScope, match); + } else if (origin.skip) { + modeBuffer += lexeme; + } else { + if (!(origin.returnEnd || origin.excludeEnd)) { + modeBuffer += lexeme; + } + processBuffer(); + if (origin.excludeEnd) { + modeBuffer = lexeme; + } + } + do { + if (top.scope) { + emitter.closeNode(); + } + if (!top.skip && !top.subLanguage) { + relevance += top.relevance; + } + top = top.parent; + } while (top !== endMode.parent); + if (endMode.starts) { + startNewMode(endMode.starts, match); + } + return origin.returnEnd ? 0 : lexeme.length; + } + + function processContinuations() { + const list = []; + for (let current = top; current !== language; current = current.parent) { + if (current.scope) { + list.unshift(current.scope); + } + } + list.forEach(item => emitter.openNode(item)); + } + + /** @type {{type?: MatchType, index?: number, rule?: Mode}}} */ + let lastMatch = {}; + + /** + * Process an individual match + * + * @param {string} textBeforeMatch - text preceding the match (since the last match) + * @param {EnhancedMatch} [match] - the match itself + */ + function processLexeme(textBeforeMatch, match) { + const lexeme = match && match[0]; + + // add non-matched text to the current mode buffer + modeBuffer += textBeforeMatch; + + if (lexeme == null) { + processBuffer(); + return 0; + } + + // we've found a 0 width match and we're stuck, so we need to advance + // this happens when we have badly behaved rules that have optional matchers to the degree that + // sometimes they can end up matching nothing at all + // Ref: https://github.com/highlightjs/highlight.js/issues/2140 + if (lastMatch.type === "begin" && match.type === "end" && lastMatch.index === match.index && lexeme === "") { + // spit the "skipped" character that our regex choked on back into the output sequence + modeBuffer += codeToHighlight.slice(match.index, match.index + 1); + if (!SAFE_MODE) { + /** @type {AnnotatedError} */ + const err = new Error(`0 width match regex (${languageName})`); + err.languageName = languageName; + err.badRule = lastMatch.rule; + throw err; + } + return 1; + } + lastMatch = match; + + if (match.type === "begin") { + return doBeginMatch(match); + } else if (match.type === "illegal" && !ignoreIllegals) { + // illegal match, we do not continue processing + /** @type {AnnotatedError} */ + const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.scope || '') + '"'); + err.mode = top; + throw err; + } else if (match.type === "end") { + const processed = doEndMatch(match); + if (processed !== NO_MATCH) { + return processed; + } + } + + // edge case for when illegal matches $ (end of line) which is technically + // a 0 width match but not a begin/end match so it's not caught by the + // first handler (when ignoreIllegals is true) + if (match.type === "illegal" && lexeme === "") { + // advance so we aren't stuck in an infinite loop + modeBuffer += "\n"; + return 1; + } + + // infinite loops are BAD, this is a last ditch catch all. if we have a + // decent number of iterations yet our index (cursor position in our + // parsing) still 3x behind our index then something is very wrong + // so we bail + if (iterations > 100000 && iterations > match.index * 3) { + const err = new Error('potential infinite loop, way more iterations than matches'); + throw err; + } + + /* + Why might be find ourselves here? An potential end match that was + triggered but could not be completed. IE, `doEndMatch` returned NO_MATCH. + (this could be because a callback requests the match be ignored, etc) + + This causes no real harm other than stopping a few times too many. + */ + + modeBuffer += lexeme; + return lexeme.length; + } + + const language = getLanguage(languageName); + if (!language) { + error(LANGUAGE_NOT_FOUND.replace("{}", languageName)); + throw new Error('Unknown language: "' + languageName + '"'); + } + + const md = compileLanguage(language); + let result = ''; + /** @type {CompiledMode} */ + let top = continuation || md; + /** @type Record */ + const continuations = {}; // keep continuations for sub-languages + const emitter = new options.__emitter(options); + processContinuations(); + let modeBuffer = ''; + let relevance = 0; + let index = 0; + let iterations = 0; + let resumeScanAtSamePosition = false; + + try { + if (!language.__emitTokens) { + top.matcher.considerAll(); + + for (;;) { + iterations++; + if (resumeScanAtSamePosition) { + // only regexes not matched previously will now be + // considered for a potential match + resumeScanAtSamePosition = false; + } else { + top.matcher.considerAll(); + } + top.matcher.lastIndex = index; + + const match = top.matcher.exec(codeToHighlight); + // console.log("match", match[0], match.rule && match.rule.begin) + + if (!match) break; + + const beforeMatch = codeToHighlight.substring(index, match.index); + const processedCount = processLexeme(beforeMatch, match); + index = match.index + processedCount; + } + processLexeme(codeToHighlight.substring(index)); + } else { + language.__emitTokens(codeToHighlight, emitter); + } + + emitter.finalize(); + result = emitter.toHTML(); + + return { + language: languageName, + value: result, + relevance, + illegal: false, + _emitter: emitter, + _top: top + }; + } catch (err) { + if (err.message && err.message.includes('Illegal')) { + return { + language: languageName, + value: escape(codeToHighlight), + illegal: true, + relevance: 0, + _illegalBy: { + message: err.message, + index, + context: codeToHighlight.slice(index - 100, index + 100), + mode: err.mode, + resultSoFar: result + }, + _emitter: emitter + }; + } else if (SAFE_MODE) { + return { + language: languageName, + value: escape(codeToHighlight), + illegal: false, + relevance: 0, + errorRaised: err, + _emitter: emitter, + _top: top + }; + } else { + throw err; + } + } + } + + /** + * returns a valid highlight result, without actually doing any actual work, + * auto highlight starts with this and it's possible for small snippets that + * auto-detection may not find a better match + * @param {string} code + * @returns {HighlightResult} + */ + function justTextHighlightResult(code) { + const result = { + value: escape(code), + illegal: false, + relevance: 0, + _top: PLAINTEXT_LANGUAGE, + _emitter: new options.__emitter(options) + }; + result._emitter.addText(code); + return result; + } + + /** + Highlighting with language detection. Accepts a string with the code to + highlight. Returns an object with the following properties: + + - language (detected language) + - relevance (int) + - value (an HTML string with highlighting markup) + - secondBest (object with the same structure for second-best heuristically + detected language, may be absent) + + @param {string} code + @param {Array} [languageSubset] + @returns {AutoHighlightResult} + */ + function highlightAuto(code, languageSubset) { + languageSubset = languageSubset || options.languages || Object.keys(languages); + const plaintext = justTextHighlightResult(code); + + const results = languageSubset.filter(getLanguage).filter(autoDetection).map(name => + _highlight(name, code, false) + ); + results.unshift(plaintext); // plaintext is always an option + + const sorted = results.sort((a, b) => { + // sort base on relevance + if (a.relevance !== b.relevance) return b.relevance - a.relevance; + + // always award the tie to the base language + // ie if C++ and Arduino are tied, it's more likely to be C++ + if (a.language && b.language) { + if (getLanguage(a.language).supersetOf === b.language) { + return 1; + } else if (getLanguage(b.language).supersetOf === a.language) { + return -1; + } + } + + // otherwise say they are equal, which has the effect of sorting on + // relevance while preserving the original ordering - which is how ties + // have historically been settled, ie the language that comes first always + // wins in the case of a tie + return 0; + }); + + const [best, secondBest] = sorted; + + /** @type {AutoHighlightResult} */ + const result = best; + result.secondBest = secondBest; + + return result; + } + + /** + * Builds new class name for block given the language name + * + * @param {HTMLElement} element + * @param {string} [currentLang] + * @param {string} [resultLang] + */ + function updateClassName(element, currentLang, resultLang) { + const language = (currentLang && aliases[currentLang]) || resultLang; + + element.classList.add("hljs"); + element.classList.add(`language-${language}`); + } + + /** + * Applies highlighting to a DOM node containing code. + * + * @param {HighlightedHTMLElement} element - the HTML element to highlight + */ + function highlightElement(element) { + /** @type HTMLElement */ + let node = null; + const language = blockLanguage(element); + + if (shouldNotHighlight(language)) return; + + fire("before:highlightElement", + { el: element, language }); + + if (element.dataset.highlighted) { + console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.", element); + return; + } + + // we should be all text, no child nodes (unescaped HTML) - this is possibly + // an HTML injection attack - it's likely too late if this is already in + // production (the code has likely already done its damage by the time + // we're seeing it)... but we yell loudly about this so that hopefully it's + // more likely to be caught in development before making it to production + if (element.children.length > 0) { + if (!options.ignoreUnescapedHTML) { + console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."); + console.warn("https://github.com/highlightjs/highlight.js/wiki/security"); + console.warn("The element with unescaped HTML:"); + console.warn(element); + } + if (options.throwUnescapedHTML) { + const err = new HTMLInjectionError( + "One of your code blocks includes unescaped HTML.", + element.innerHTML + ); + throw err; + } + } + + node = element; + const text = node.textContent; + const result = language ? highlight(text, { language, ignoreIllegals: true }) : highlightAuto(text); + + element.innerHTML = result.value; + element.dataset.highlighted = "yes"; + updateClassName(element, language, result.language); + element.result = { + language: result.language, + // TODO: remove with version 11.0 + re: result.relevance, + relevance: result.relevance + }; + if (result.secondBest) { + element.secondBest = { + language: result.secondBest.language, + relevance: result.secondBest.relevance + }; + } + + fire("after:highlightElement", { el: element, result, text }); + } + + /** + * Updates highlight.js global options with the passed options + * + * @param {Partial} userOptions + */ + function configure(userOptions) { + options = inherit(options, userOptions); + } + + // TODO: remove v12, deprecated + const initHighlighting = () => { + highlightAll(); + deprecated("10.6.0", "initHighlighting() deprecated. Use highlightAll() now."); + }; + + // TODO: remove v12, deprecated + function initHighlightingOnLoad() { + highlightAll(); + deprecated("10.6.0", "initHighlightingOnLoad() deprecated. Use highlightAll() now."); + } + + let wantsHighlight = false; + + /** + * auto-highlights all pre>code elements on the page + */ + function highlightAll() { + function boot() { + // if a highlight was requested before DOM was loaded, do now + highlightAll(); + } + + // if we are called too early in the loading process + if (document.readyState === "loading") { + // make sure the event listener is only added once + if (!wantsHighlight) { + window.addEventListener('DOMContentLoaded', boot, false); + } + wantsHighlight = true; + return; + } + + const blocks = document.querySelectorAll(options.cssSelector); + blocks.forEach(highlightElement); + } + + /** + * Register a language grammar module + * + * @param {string} languageName + * @param {LanguageFn} languageDefinition + */ + function registerLanguage(languageName, languageDefinition) { + let lang = null; + try { + lang = languageDefinition(hljs); + } catch (error$1) { + error("Language definition for '{}' could not be registered.".replace("{}", languageName)); + // hard or soft error + if (!SAFE_MODE) { throw error$1; } else { error(error$1); } + // languages that have serious errors are replaced with essentially a + // "plaintext" stand-in so that the code blocks will still get normal + // css classes applied to them - and one bad language won't break the + // entire highlighter + lang = PLAINTEXT_LANGUAGE; + } + // give it a temporary name if it doesn't have one in the meta-data + if (!lang.name) lang.name = languageName; + languages[languageName] = lang; + lang.rawDefinition = languageDefinition.bind(null, hljs); + + if (lang.aliases) { + registerAliases(lang.aliases, { languageName }); + } + } + + /** + * Remove a language grammar module + * + * @param {string} languageName + */ + function unregisterLanguage(languageName) { + delete languages[languageName]; + for (const alias of Object.keys(aliases)) { + if (aliases[alias] === languageName) { + delete aliases[alias]; + } + } + } + + /** + * @returns {string[]} List of language internal names + */ + function listLanguages() { + return Object.keys(languages); + } + + /** + * @param {string} name - name of the language to retrieve + * @returns {Language | undefined} + */ + function getLanguage(name) { + name = (name || '').toLowerCase(); + return languages[name] || languages[aliases[name]]; + } + + /** + * + * @param {string|string[]} aliasList - single alias or list of aliases + * @param {{languageName: string}} opts + */ + function registerAliases(aliasList, { languageName }) { + if (typeof aliasList === 'string') { + aliasList = [aliasList]; + } + aliasList.forEach(alias => { aliases[alias.toLowerCase()] = languageName; }); + } + + /** + * Determines if a given language has auto-detection enabled + * @param {string} name - name of the language + */ + function autoDetection(name) { + const lang = getLanguage(name); + return lang && !lang.disableAutodetect; + } + + /** + * Upgrades the old highlightBlock plugins to the new + * highlightElement API + * @param {HLJSPlugin} plugin + */ + function upgradePluginAPI(plugin) { + // TODO: remove with v12 + if (plugin["before:highlightBlock"] && !plugin["before:highlightElement"]) { + plugin["before:highlightElement"] = (data) => { + plugin["before:highlightBlock"]( + Object.assign({ block: data.el }, data) + ); + }; + } + if (plugin["after:highlightBlock"] && !plugin["after:highlightElement"]) { + plugin["after:highlightElement"] = (data) => { + plugin["after:highlightBlock"]( + Object.assign({ block: data.el }, data) + ); + }; + } + } + + /** + * @param {HLJSPlugin} plugin + */ + function addPlugin(plugin) { + upgradePluginAPI(plugin); + plugins.push(plugin); + } + + /** + * @param {HLJSPlugin} plugin + */ + function removePlugin(plugin) { + const index = plugins.indexOf(plugin); + if (index !== -1) { + plugins.splice(index, 1); + } + } + + /** + * + * @param {PluginEvent} event + * @param {any} args + */ + function fire(event, args) { + const cb = event; + plugins.forEach(function(plugin) { + if (plugin[cb]) { + plugin[cb](args); + } + }); + } + + /** + * DEPRECATED + * @param {HighlightedHTMLElement} el + */ + function deprecateHighlightBlock(el) { + deprecated("10.7.0", "highlightBlock will be removed entirely in v12.0"); + deprecated("10.7.0", "Please use highlightElement now."); + + return highlightElement(el); + } + + /* Interface definition */ + Object.assign(hljs, { + highlight, + highlightAuto, + highlightAll, + highlightElement, + // TODO: Remove with v12 API + highlightBlock: deprecateHighlightBlock, + configure, + initHighlighting, + initHighlightingOnLoad, + registerLanguage, + unregisterLanguage, + listLanguages, + getLanguage, + registerAliases, + autoDetection, + inherit, + addPlugin, + removePlugin + }); + + hljs.debugMode = function() { SAFE_MODE = false; }; + hljs.safeMode = function() { SAFE_MODE = true; }; + hljs.versionString = version; + + hljs.regex = { + concat: concat, + lookahead: lookahead, + either: either, + optional: optional, + anyNumberOfTimes: anyNumberOfTimes + }; + + for (const key in MODES) { + // @ts-ignore + if (typeof MODES[key] === "object") { + // @ts-ignore + deepFreeze(MODES[key]); + } + } + + // merge all the modes/regexes into our main object + Object.assign(hljs, MODES); + + return hljs; + }; + + // Other names for the variable may break build script + const highlight = HLJS({}); + + // returns a new instance of the highlighter to be used for extensions + // check https://github.com/wooorm/lowlight/issues/47 + highlight.newInstance = () => HLJS({}); + + // https://docs.oracle.com/javase/specs/jls/se15/html/jls-3.html#jls-3.10 + var decimalDigits = '[0-9](_*[0-9])*'; + var frac = `\\.(${decimalDigits})`; + var hexDigits = '[0-9a-fA-F](_*[0-9a-fA-F])*'; + var NUMERIC = { + className: 'number', + variants: [ + // DecimalFloatingPointLiteral + // including ExponentPart + { begin: `(\\b(${decimalDigits})((${frac})|\\.)?|(${frac}))` + + `[eE][+-]?(${decimalDigits})[fFdD]?\\b` }, + // excluding ExponentPart + { begin: `\\b(${decimalDigits})((${frac})[fFdD]?\\b|\\.([fFdD]\\b)?)` }, + { begin: `(${frac})[fFdD]?\\b` }, + { begin: `\\b(${decimalDigits})[fFdD]\\b` }, + + // HexadecimalFloatingPointLiteral + { begin: `\\b0[xX]((${hexDigits})\\.?|(${hexDigits})?\\.(${hexDigits}))` + + `[pP][+-]?(${decimalDigits})[fFdD]?\\b` }, + + // DecimalIntegerLiteral + { begin: '\\b(0|[1-9](_*[0-9])*)[lL]?\\b' }, + + // HexIntegerLiteral + { begin: `\\b0[xX](${hexDigits})[lL]?\\b` }, + + // OctalIntegerLiteral + { begin: '\\b0(_*[0-7])*[lL]?\\b' }, + + // BinaryIntegerLiteral + { begin: '\\b0[bB][01](_*[01])*[lL]?\\b' }, + ], + relevance: 0 + }; + + /* + Language: Java + Author: Vsevolod Solovyov + Category: common, enterprise + Website: https://www.java.com/ + */ + + + /** + * Allows recursive regex expressions to a given depth + * + * ie: recurRegex("(abc~~~)", /~~~/g, 2) becomes: + * (abc(abc(abc))) + * + * @param {string} re + * @param {RegExp} substitution (should be a g mode regex) + * @param {number} depth + * @returns {string}`` + */ + function recurRegex(re, substitution, depth) { + if (depth === -1) return ""; + + return re.replace(substitution, _ => { + return recurRegex(re, substitution, depth - 1); + }); + } + + /** @type LanguageFn */ + function java(hljs) { + const regex = hljs.regex; + const JAVA_IDENT_RE = '[\u00C0-\u02B8a-zA-Z_$][\u00C0-\u02B8a-zA-Z_$0-9]*'; + const TYPE_ARG_RE = '(?:(?:' + JAVA_IDENT_RE + '~~~)|(?:\\?\\s+(?:extends|super)\\s+' + JAVA_IDENT_RE + '~~~)|(?:\\?))'; + const GENERIC_RE = recurRegex('(?:<' + TYPE_ARG_RE + '(?:\\s*,\\s*' + TYPE_ARG_RE + ')*>)?', /~~~/g, 2); + const ARRAY_RE = '(?:(?:\\[])+)?'; + const MAIN_KEYWORDS = [ + 'synchronized', + 'abstract', + 'private', + 'var', + 'static', + 'if', + 'const ', + 'for', + 'while', + 'strictfp', + 'finally', + 'protected', + 'import', + 'native', + 'final', + 'void', + 'enum', + 'else', + 'break', + 'transient', + 'catch', + 'instanceof', + 'volatile', + 'case', + 'assert', + 'package', + 'default', + 'public', + 'try', + 'switch', + 'continue', + 'throws', + 'protected', + 'public', + 'private', + 'module', + 'requires', + 'exports', + 'do', + 'sealed', + 'yield', + 'permits', + 'goto', + 'when' + ]; + + const BUILT_INS = [ + 'super', + 'this' + ]; + + const LITERALS = [ + 'false', + 'true', + 'null' + ]; + + const TYPES = [ + 'char', + 'boolean', + 'long', + 'float', + 'int', + 'byte', + 'short', + 'double' + ]; + + const KEYWORDS = { + keyword: MAIN_KEYWORDS, + literal: LITERALS, + type: TYPES, + built_in: BUILT_INS + }; + + const ANNOTATION = { + className: 'meta', + begin: '@' + JAVA_IDENT_RE, + contains: [ + { + begin: /\(/, + end: /\)/, + contains: [ "self" ] // allow nested () inside our annotation + } + ] + }; + const PARAMS = { + className: 'params', + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + relevance: 0, + contains: [ hljs.C_BLOCK_COMMENT_MODE ], + endsParent: true + }; + + return { + name: 'Java', + aliases: [ 'jsp' ], + keywords: KEYWORDS, + illegal: /<\/|#/, + contains: [ + hljs.COMMENT( + '/\\*\\*', + '\\*/', + { + relevance: 0, + contains: [ + { + // eat up @'s in emails to prevent them to be recognized as doctags + begin: /\w+@/, + relevance: 0 + }, + { + className: 'doctag', + begin: '@[A-Za-z]+' + } + ] + } + ), + // relevance boost + { + begin: /import java\.[a-z]+\./, + keywords: "import", + relevance: 2 + }, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + { + begin: /"""/, + end: /"""/, + className: "string", + contains: [ hljs.BACKSLASH_ESCAPE ] + }, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + { + match: [ + /\b(?:class|interface|enum|extends|implements|new)/, + /\s+/, + JAVA_IDENT_RE + ], + className: { + 1: "keyword", + 3: "title.class" + } + }, + { + // Exceptions for hyphenated keywords + match: /non-sealed/, + scope: "keyword" + }, + { + begin: [ + regex.concat(/(?!else)/, JAVA_IDENT_RE), + GENERIC_RE, + ARRAY_RE, + /\s+/, + JAVA_IDENT_RE, + /\s+/, + /=(?!=)/ + ], + className: { + 1: "type", + 5: "variable", + 7: "operator" + } + }, + { + begin: [ + /record/, + /\s+/, + JAVA_IDENT_RE + ], + className: { + 1: "keyword", + 3: "title.class" + }, + contains: [ + PARAMS, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + { + // Expression keywords prevent 'keyword Name(...)' from being + // recognized as a function definition + beginKeywords: 'new throw return else', + relevance: 0 + }, + { + begin: [ + '(?:' + JAVA_IDENT_RE + GENERIC_RE + ARRAY_RE + '\\s+)', + hljs.UNDERSCORE_IDENT_RE, + /\s*(?=\()/ + ], + className: { 2: "title.function" }, + keywords: KEYWORDS, + contains: [ + { + className: 'params', + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + relevance: 0, + contains: [ + ANNOTATION, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + NUMERIC, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + NUMERIC, + ANNOTATION + ] + }; + } + + /* + Language: .properties + Contributors: Valentin Aitken , Egor Rogov + Website: https://en.wikipedia.org/wiki/.properties + Category: config + */ + + /** @type LanguageFn */ + function properties(hljs) { + // whitespaces: space, tab, formfeed + const WS0 = '[ \\t\\f]*'; + const WS1 = '[ \\t\\f]+'; + // delimiter + const EQUAL_DELIM = WS0 + '[:=]' + WS0; + const WS_DELIM = WS1; + const DELIM = '(' + EQUAL_DELIM + '|' + WS_DELIM + ')'; + const KEY = '([^\\\\:= \\t\\f\\n]|\\\\.)+'; + + const DELIM_AND_VALUE = { + // skip DELIM + end: DELIM, + relevance: 0, + starts: { + // value: everything until end of line (again, taking into account backslashes) + className: 'string', + end: /$/, + relevance: 0, + contains: [ + { begin: '\\\\\\\\' }, + { begin: '\\\\\\n' } + ] + } + }; + + return { + name: '.properties', + disableAutodetect: true, + case_insensitive: true, + illegal: /\S/, + contains: [ + hljs.COMMENT('^\\s*[!#]', '$'), + // key: everything until whitespace or = or : (taking into account backslashes) + // case of a key-value pair + { + returnBegin: true, + variants: [ + { begin: KEY + EQUAL_DELIM }, + { begin: KEY + WS_DELIM } + ], + contains: [ + { + className: 'attr', + begin: KEY, + endsParent: true + } + ], + starts: DELIM_AND_VALUE + }, + // case of an empty key + { + className: 'attr', + begin: KEY + WS0 + '$' + } + ] + }; + } + + /* + Language: HTML, XML + Website: https://www.w3.org/XML/ + Category: common, web + Audit: 2020 + */ + + /** @type LanguageFn */ + function xml(hljs) { + const regex = hljs.regex; + // XML names can have the following additional letters: https://www.w3.org/TR/xml/#NT-NameChar + // OTHER_NAME_CHARS = /[:\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]/; + // Element names start with NAME_START_CHAR followed by optional other Unicode letters, ASCII digits, hyphens, underscores, and periods + // const TAG_NAME_RE = regex.concat(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/, regex.optional(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*:/), /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*/);; + // const XML_IDENT_RE = /[A-Z_a-z:\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]+/; + // const TAG_NAME_RE = regex.concat(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/, regex.optional(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*:/), /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*/); + // however, to cater for performance and more Unicode support rely simply on the Unicode letter class + const TAG_NAME_RE = regex.concat(/[\p{L}_]/u, regex.optional(/[\p{L}0-9_.-]*:/u), /[\p{L}0-9_.-]*/u); + const XML_IDENT_RE = /[\p{L}0-9._:-]+/u; + const XML_ENTITIES = { + className: 'symbol', + begin: /&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/ + }; + const XML_META_KEYWORDS = { + begin: /\s/, + contains: [ + { + className: 'keyword', + begin: /#?[a-z_][a-z1-9_-]+/, + illegal: /\n/ + } + ] + }; + const XML_META_PAR_KEYWORDS = hljs.inherit(XML_META_KEYWORDS, { + begin: /\(/, + end: /\)/ + }); + const APOS_META_STRING_MODE = hljs.inherit(hljs.APOS_STRING_MODE, { className: 'string' }); + const QUOTE_META_STRING_MODE = hljs.inherit(hljs.QUOTE_STRING_MODE, { className: 'string' }); + const TAG_INTERNALS = { + endsWithParent: true, + illegal: /`]+/ } + ] + } + ] + } + ] + }; + return { + name: 'HTML, XML', + aliases: [ + 'html', + 'xhtml', + 'rss', + 'atom', + 'xjb', + 'xsd', + 'xsl', + 'plist', + 'wsf', + 'svg' + ], + case_insensitive: true, + unicodeRegex: true, + contains: [ + { + className: 'meta', + begin: //, + relevance: 10, + contains: [ + XML_META_KEYWORDS, + QUOTE_META_STRING_MODE, + APOS_META_STRING_MODE, + XML_META_PAR_KEYWORDS, + { + begin: /\[/, + end: /\]/, + contains: [ + { + className: 'meta', + begin: //, + contains: [ + XML_META_KEYWORDS, + XML_META_PAR_KEYWORDS, + QUOTE_META_STRING_MODE, + APOS_META_STRING_MODE + ] + } + ] + } + ] + }, + hljs.COMMENT( + //, + { relevance: 10 } + ), + { + begin: //, + relevance: 10 + }, + XML_ENTITIES, + // xml processing instructions + { + className: 'meta', + end: /\?>/, + variants: [ + { + begin: /<\?xml/, + relevance: 10, + contains: [ + QUOTE_META_STRING_MODE + ] + }, + { + begin: /<\?[a-z][a-z0-9]+/, + } + ] + + }, + { + className: 'tag', + /* + The lookahead pattern (?=...) ensures that 'begin' only matches + ')/, + end: />/, + keywords: { name: 'style' }, + contains: [ TAG_INTERNALS ], + starts: { + end: /<\/style>/, + returnEnd: true, + subLanguage: [ + 'css', + 'xml' + ] + } + }, + { + className: 'tag', + // See the comment in the