From 134c3ef41e774b483bcce32ce2fe0ef416017728 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Thu, 11 Sep 2025 00:05:02 +0000 Subject: [PATCH 0001/1116] 8367293: RISC-V: enable vectorapi test for VectorMask.laneIsSet Reviewed-by: fyang, epeter --- .../vectorapi/VectorMaskLaneIsSetTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java index b7f2103c56c..17d483f1b16 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskLaneIsSetTest.java @@ -69,7 +69,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 6" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 6" }, applyIfCPUFeature = { "avx2", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 6" }, applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testVectorMaskLaneIsSetByte_const() { Asserts.assertEquals(ma[0], mask_b.laneIsSet(0)); Asserts.assertEquals(ma[0], mask_s.laneIsSet(0)); @@ -81,7 +81,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Byte_variable(int i) { return mask_b.laneIsSet(i); } @@ -93,7 +93,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Short_variable(int i) { return mask_s.laneIsSet(i); } @@ -105,7 +105,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Int_variable(int i) { return mask_i.laneIsSet(i); } @@ -117,7 +117,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx2", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Long_variable(int i) { return mask_l.laneIsSet(i); } @@ -129,7 +129,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Float_variable(int i) { return mask_f.laneIsSet(i); } @@ -141,7 +141,7 @@ public class VectorMaskLaneIsSetTest { @Test @IR(counts = { IRNode.VECTOR_MASK_LANE_IS_SET, "= 1" }, applyIfCPUFeature = { "asimd", "true" }) - @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeature = { "avx2", "true" }) + @IR(counts = { IRNode.VECTOR_MASK_TO_LONG, "= 1" }, applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static boolean testVectorMaskLaneIsSet_Double_variable(int i) { return mask_d.laneIsSet(i); } From eb9e04598db7a70347ada005035644012026f902 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 11 Sep 2025 04:59:07 +0000 Subject: [PATCH 0002/1116] 8361530: Test javax/swing/GraphicsConfigNotifier/StalePreferredSize.java timed out Reviewed-by: psadhukhan --- .../swing/GraphicsConfigNotifier/StalePreferredSize.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java b/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java index 371c6fb43ef..3be7d08870d 100644 --- a/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java +++ b/test/jdk/javax/swing/GraphicsConfigNotifier/StalePreferredSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, 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 @@ -66,9 +66,8 @@ import static javax.swing.UIManager.getInstalledLookAndFeels; * It is checked by SwingUtilities.updateComponentTreeUI(), if layout * was correct the call to updateComponentTreeUI() will be no-op. * @compile -encoding utf-8 StalePreferredSize.java - * @run main/othervm/timeout=600 StalePreferredSize - * @run main/othervm/timeout=600 -Dsun.java2d.uiScale=1 StalePreferredSize - * @run main/othervm/timeout=600 -Dsun.java2d.uiScale=2.25 StalePreferredSize + * @run main/othervm/timeout=420 StalePreferredSize + * @run main/othervm/timeout=420 -Dsun.java2d.uiScale=2.25 StalePreferredSize */ public final class StalePreferredSize { @@ -92,7 +91,7 @@ public final class StalePreferredSize { public static void main(final String[] args) throws Exception { for (final UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) { EventQueue.invokeAndWait(() -> setLookAndFeel(laf)); - for (typeFont = 0; typeFont < 3; typeFont++) { + for (typeFont = 0; typeFont < 1; typeFont++) { System.err.println("typeFont = " + typeFont); for (boolean usePopup : new boolean[]{true, false}) { addViaPopup = usePopup; From 4cc75be80e6a89e0ed293e2f8bbb6d0f94189468 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 11 Sep 2025 05:03:21 +0000 Subject: [PATCH 0003/1116] 8366702: C2 SuperWord: refactor VTransform vector nodes Reviewed-by: chagedorn, galder --- .../share/opto/superwordVTransformBuilder.cpp | 110 +++++---- .../share/opto/superwordVTransformBuilder.hpp | 4 +- src/hotspot/share/opto/vtransform.cpp | 211 +++++++++--------- src/hotspot/share/opto/vtransform.hpp | 139 ++++++++++-- 4 files changed, 286 insertions(+), 178 deletions(-) diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index b31f2eda9c0..dbc96c234a9 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -80,11 +80,13 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ vtn_memory_dependencies.clear(); // Add every memory dependency only once per vtn. if (p0->is_Load()) { + init_req_with_scalar(p0, vtn, MemNode::Control); init_req_with_scalar(p0, vtn, MemNode::Address); for (uint k = 0; k < pack->size(); k++) { add_memory_dependencies_of_node_to_vtnode(pack->at(k), vtn, vtn_memory_dependencies); } } else if (p0->is_Store()) { + init_req_with_scalar(p0, vtn, MemNode::Control); init_req_with_scalar(p0, vtn, MemNode::Address); init_req_with_vector(pack, vtn, MemNode::ValueIn); for (uint k = 0; k < pack->size(); k++) { @@ -93,26 +95,27 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ } else if (vtn->isa_ReductionVector() != nullptr) { init_req_with_scalar(p0, vtn, 1); // scalar init init_req_with_vector(pack, vtn, 2); // vector - } else { - assert(vtn->isa_ElementWiseVector() != nullptr, "all other vtnodes are handled above"); - if (VectorNode::is_scalar_rotate(p0) && - p0->in(2)->is_Con() && - Matcher::supports_vector_constant_rotates(p0->in(2)->get_int())) { - init_req_with_vector(pack, vtn, 1); - init_req_with_scalar(p0, vtn, 2); // constant rotation - } else if (VectorNode::is_roundopD(p0)) { - init_req_with_vector(pack, vtn, 1); - init_req_with_scalar(p0, vtn, 2); // constant rounding mode - } else if (p0->is_CMove()) { - // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. - set_all_req_with_vectors(pack, vtn); - VTransformBoolVectorNode* vtn_mask_cmp = vtn->in_req(1)->isa_BoolVector(); - if (vtn_mask_cmp->test()._is_negated) { - vtn->swap_req(2, 3); // swap if test was negated. - } - } else { - set_all_req_with_vectors(pack, vtn); + } else if (VectorNode::is_scalar_rotate(p0) && + p0->in(2)->is_Con() && + Matcher::supports_vector_constant_rotates(p0->in(2)->get_int())) { + init_req_with_vector(pack, vtn, 1); + init_req_with_scalar(p0, vtn, 2); // constant rotation + } else if (VectorNode::is_roundopD(p0)) { + init_req_with_vector(pack, vtn, 1); + init_req_with_scalar(p0, vtn, 2); // constant rounding mode + } else if (p0->is_CMove()) { + // Cmp + Bool + CMove -> VectorMaskCmp + VectorBlend. + init_all_req_with_vectors(pack, vtn); + // Inputs must be permuted from (mask, blend1, blend2) -> (blend1, blend2, mask) + vtn->swap_req(1, 2); + vtn->swap_req(2, 3); + // If the test was negated: (blend1, blend2, mask) -> (blend2, blend1, mask) + VTransformBoolVectorNode* vtn_mask_cmp = vtn->in_req(3)->isa_BoolVector(); + if (vtn_mask_cmp->test()._is_negated) { + vtn->swap_req(1, 2); // swap if test was negated. } + } else { + init_all_req_with_vectors(pack, vtn); } } } @@ -139,51 +142,72 @@ void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_ init_req_with_scalar(n, vtn, 0); continue; } else { - set_all_req_with_scalars(n, vtn); + init_all_req_with_scalars(n, vtn); } } } // Create a vtnode for each pack. No in/out edges set yet. VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(const Node_List* pack) const { - uint pack_size = pack->size(); Node* p0 = pack->at(0); - int opc = p0->Opcode(); - VTransformVectorNode* vtn = nullptr; + const VTransformVectorNodeProperties properties = VTransformVectorNodeProperties::make_from_pack(pack, _vloop_analyzer); + const int sopc = properties.scalar_opcode(); + const uint vlen = properties.vector_length(); + const BasicType bt = properties.element_basic_type(); + VTransformVectorNode* vtn = nullptr; if (p0->is_Load()) { const VPointer& scalar_p = _vloop_analyzer.vpointers().vpointer(p0->as_Load()); - const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * pack_size)); - vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, pack_size, vector_p); + const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * vlen)); + vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, properties, vector_p, p0->adr_type()); } else if (p0->is_Store()) { const VPointer& scalar_p = _vloop_analyzer.vpointers().vpointer(p0->as_Store()); - const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * pack_size)); - vtn = new (_vtransform.arena()) VTransformStoreVectorNode(_vtransform, pack_size, vector_p); + const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * vlen)); + vtn = new (_vtransform.arena()) VTransformStoreVectorNode(_vtransform, properties, vector_p, p0->adr_type()); + } else if (p0->is_Cmp()) { + vtn = new (_vtransform.arena()) VTransformCmpVectorNode(_vtransform, properties); } else if (p0->is_Bool()) { VTransformBoolTest kind = _packset.get_bool_test(pack); - vtn = new (_vtransform.arena()) VTransformBoolVectorNode(_vtransform, pack_size, kind); + vtn = new (_vtransform.arena()) VTransformBoolVectorNode(_vtransform, properties, kind); + } else if (p0->is_CMove()) { + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, Op_VectorBlend); } else if (_vloop_analyzer.reductions().is_marked_reduction(p0)) { - vtn = new (_vtransform.arena()) VTransformReductionVectorNode(_vtransform, pack_size); + vtn = new (_vtransform.arena()) VTransformReductionVectorNode(_vtransform, properties); } else if (VectorNode::is_muladds2i(p0)) { // A special kind of binary element-wise vector op: the inputs are "ints" a and b, // but reinterpreted as two "shorts" [a0, a1] and [b0, b1]: // v = MulAddS2I(a, b) = a0 * b0 + a1 + b1 assert(p0->req() == 5, "MulAddS2I should have 4 operands"); - vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, 3, pack_size); + int vopc = VectorNode::opcode(sopc, bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, 3, properties, vopc); + } else if (VectorNode::is_convert_opcode(sopc)) { + assert(p0->req() == 2, "convert should have 2 operands"); + BasicType def_bt = _vloop_analyzer.types().velt_basic_type(p0->in(1)); + int vopc = VectorCastNode::opcode(sopc, def_bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, vopc); + } else if (VectorNode::is_reinterpret_opcode(sopc)) { + assert(p0->req() == 2, "reinterpret should have 2 operands"); + BasicType src_bt = _vloop_analyzer.types().velt_basic_type(p0->in(1)); + vtn = new (_vtransform.arena()) VTransformReinterpretVectorNode(_vtransform, properties, src_bt); + } else if (VectorNode::can_use_RShiftI_instead_of_URShiftI(p0, bt)) { + int vopc = VectorNode::opcode(Op_RShiftI, bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, vopc); + } else if (VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(sopc)) { + vtn = new (_vtransform.arena()) VTransformElementWiseLongOpWithCastToIntVectorNode(_vtransform, properties); } else { assert(p0->req() == 3 || - p0->is_CMove() || - VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(opc) || - VectorNode::is_convert_opcode(opc) || - VectorNode::is_reinterpret_opcode(opc) || - VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc) || - opc == Op_FmaD || - opc == Op_FmaF || - opc == Op_FmaHF || - opc == Op_SignumF || - opc == Op_SignumD, + VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(sopc) || + VectorNode::is_reinterpret_opcode(sopc) || + VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(sopc) || + sopc == Op_FmaD || + sopc == Op_FmaF || + sopc == Op_FmaHF || + sopc == Op_SignumF || + sopc == Op_SignumD, "pack type must be in this list"); - vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), pack_size); + assert(!VectorNode::is_roundopD(p0) || p0->in(2)->is_Con(), "rounding mode must be constant"); + int vopc = VectorNode::opcode(sopc, bt); + vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, vopc); } vtn->set_nodes(pack); return vtn; @@ -291,7 +315,7 @@ void SuperWordVTransformBuilder::init_req_with_vector(const Node_List* pack, VTr vtn->init_req(j, req); } -void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNode* vtn) { +void SuperWordVTransformBuilder::init_all_req_with_scalars(Node* n, VTransformNode* vtn) { assert(vtn->req() == n->req(), "scalars must have same number of reqs"); for (uint j = 0; j < n->req(); j++) { Node* def = n->in(j); @@ -300,7 +324,7 @@ void SuperWordVTransformBuilder::set_all_req_with_scalars(Node* n, VTransformNod } } -void SuperWordVTransformBuilder::set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn) { +void SuperWordVTransformBuilder::init_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn) { Node* p0 = pack->at(0); assert(vtn->req() <= p0->req(), "must have at at most as many reqs"); // Vectors have no ctrl, so ignore it. diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp index ea93bb60ffb..6ed8480209a 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.hpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -79,8 +79,8 @@ private: VTransformNode* get_vtnode_or_wrap_as_outer(Node* n); void init_req_with_scalar(Node* n, VTransformNode* vtn, const int index); void init_req_with_vector(const Node_List* pack, VTransformNode* vtn, const int index); - void set_all_req_with_scalars(Node* n, VTransformNode* vtn); - void set_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn); + void init_all_req_with_scalars(Node* n, VTransformNode* vtn); + void init_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn); void add_memory_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies); }; diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 2f77c1c2e37..8c1210a5a09 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -104,7 +104,7 @@ bool VTransformGraph::schedule() { } #ifndef PRODUCT - if (_trace._verbose) { + if (_trace._info) { print_schedule(); } #endif @@ -158,11 +158,9 @@ void VTransform::apply_speculative_alignment_runtime_checks() { const GrowableArray& vtnodes = _graph.vtnodes(); for (int i = 0; i < vtnodes.length(); i++) { - VTransformVectorNode* vtn = vtnodes.at(i)->isa_Vector(); + VTransformMemVectorNode* vtn = vtnodes.at(i)->isa_MemVector(); if (vtn == nullptr) { continue; } - MemNode* p0 = vtn->nodes().at(0)->isa_Mem(); - if (p0 == nullptr) { continue; } - const VPointer& vp = vpointer(p0); + const VPointer& vp = vtn->vpointer(); if (vp.mem_pointer().base().is_object()) { continue; } assert(vp.mem_pointer().base().is_native(), "VPointer base must be object or native"); @@ -720,41 +718,41 @@ Node* VTransformApplyState::transformed_node(const VTransformNode* vtn) const { } VTransformApplyResult VTransformMemopScalarNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformDataScalarNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformLoopPhiNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformCFGNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformOuterNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwap without touching the inputs. + // This was just wrapped. Now we simply unwrap without touching the inputs. return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformReplicateNode::apply(VTransformApplyState& apply_state) const { Node* val = apply_state.transformed_node(in_req(1)); VectorNode* vn = VectorNode::scalar2vector(val, _vlen, _element_type); - register_new_node_from_vectorization(apply_state, vn, val); - return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); + register_new_node_from_vectorization(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformConvI2LNode::apply(VTransformApplyState& apply_state) const { Node* val = apply_state.transformed_node(in_req(1)); Node* n = new ConvI2LNode(val); - register_new_node_from_vectorization(apply_state, n, val); + register_new_node_from_vectorization(apply_state, n); return VTransformApplyResult::make_scalar(n); } @@ -766,11 +764,11 @@ VTransformApplyResult VTransformShiftCountNode::apply(VTransformApplyState& appl // bits in a scalar shift operation. But vector shift does not truncate, so // we must apply the mask now. Node* shift_count_masked = new AndINode(shift_count_in, phase->intcon(_mask)); - register_new_node_from_vectorization(apply_state, shift_count_masked, shift_count_in); + register_new_node_from_vectorization(apply_state, shift_count_masked); // Now that masked value is "boadcast" (some platforms only set the lowest element). VectorNode* vn = VectorNode::shift_count(_shift_opcode, shift_count_masked, _vlen, _element_bt); - register_new_node_from_vectorization(apply_state, vn, shift_count_in); - return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); + register_new_node_from_vectorization(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } @@ -781,77 +779,62 @@ VTransformApplyResult VTransformPopulateIndexNode::apply(VTransformApplyState& a assert(VectorNode::is_populate_index_supported(_element_bt), "should support"); const TypeVect* vt = TypeVect::make(_element_bt, _vlen); VectorNode* vn = new PopulateIndexNode(val, phase->intcon(1), vt); - register_new_node_from_vectorization(apply_state, vn, val); - return VTransformApplyResult::make_vector(vn, _vlen, vn->length_in_bytes()); + register_new_node_from_vectorization(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformElementWiseVectorNode::apply(VTransformApplyState& apply_state) const { - Node* first = nodes().at(0); - uint vlen = nodes().length(); - int opc = first->Opcode(); - BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); - - if (first->is_Cmp()) { - // Cmp + Bool -> VectorMaskCmp - // Handled by Bool / VTransformBoolVectorNode, so we do not generate any nodes here. - return VTransformApplyResult::make_empty(); - } - assert(2 <= req() && req() <= 4, "Must have 1-3 inputs"); - VectorNode* vn = nullptr; + const TypeVect* vt = TypeVect::make(element_basic_type(), vector_length()); Node* in1 = apply_state.transformed_node(in_req(1)); Node* in2 = (req() >= 3) ? apply_state.transformed_node(in_req(2)) : nullptr; - Node* in3 = (req() >= 4) ? apply_state.transformed_node(in_req(3)) : nullptr; - if (first->is_CMove()) { - assert(req() == 4, "three inputs expected: mask, blend1, blend2"); - vn = new VectorBlendNode(/* blend1 */ in2, /* blend2 */ in3, /* mask */ in1); - } else if (VectorNode::is_convert_opcode(opc)) { - assert(first->req() == 2 && req() == 2, "only one input expected"); - int vopc = VectorCastNode::opcode(opc, in1->bottom_type()->is_vect()->element_basic_type()); - vn = VectorCastNode::make(vopc, in1, bt, vlen); - } else if (VectorNode::is_reinterpret_opcode(opc)) { - assert(first->req() == 2 && req() == 2, "only one input expected"); - const TypeVect* vt = TypeVect::make(bt, vlen); - vn = new VectorReinterpretNode(in1, in1->bottom_type()->is_vect(), vt); - } else if (VectorNode::can_use_RShiftI_instead_of_URShiftI(first, bt)) { - opc = Op_RShiftI; - vn = VectorNode::make(opc, in1, in2, vlen, bt); - } else if (VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(opc)) { - // The scalar operation was a long -> int operation. - // However, the vector operation is long -> long. - VectorNode* long_vn = VectorNode::make(opc, in1, nullptr, vlen, T_LONG); - register_new_node_from_vectorization(apply_state, long_vn, first); - // Cast long -> int, to mimic the scalar long -> int operation. - vn = VectorCastNode::make(Op_VectorCastL2X, long_vn, T_INT, vlen); - } else if (req() == 3 || - VectorNode::is_scalar_unary_op_with_equal_input_and_output_types(opc)) { - assert(!VectorNode::is_roundopD(first) || in2->is_Con(), "rounding mode must be constant"); - vn = VectorNode::make(opc, in1, in2, vlen, bt); // unary and binary + VectorNode* vn = nullptr; + if (req() <= 3) { + vn = VectorNode::make(_vector_opcode, in1, in2, vt); // unary and binary } else { - assert(req() == 4, "three inputs expected"); - assert(opc == Op_FmaD || - opc == Op_FmaF || - opc == Op_FmaHF || - opc == Op_SignumF || - opc == Op_SignumD, - "element wise operation must be from this list"); - vn = VectorNode::make(opc, in1, in2, in3, vlen, bt); // ternary + Node* in3 = apply_state.transformed_node(in_req(3)); + vn = VectorNode::make(_vector_opcode, in1, in2, in3, vt); // ternary } register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->length_in_bytes()); + return VTransformApplyResult::make_vector(vn); +} + +VTransformApplyResult VTransformElementWiseLongOpWithCastToIntVectorNode::apply(VTransformApplyState& apply_state) const { + uint vlen = vector_length(); + int sopc = scalar_opcode(); + Node* in1 = apply_state.transformed_node(in_req(1)); + + // The scalar operation was a long -> int operation. + // However, the vector operation is long -> long. + VectorNode* long_vn = VectorNode::make(sopc, in1, nullptr, vlen, T_LONG); + register_new_node_from_vectorization(apply_state, long_vn); + // Cast long -> int, to mimic the scalar long -> int operation. + VectorNode* vn = VectorCastNode::make(Op_VectorCastL2X, long_vn, T_INT, vlen); + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + return VTransformApplyResult::make_vector(vn); +} + +VTransformApplyResult VTransformReinterpretVectorNode::apply(VTransformApplyState& apply_state) const { + const TypeVect* dst_vt = TypeVect::make(element_basic_type(), vector_length()); + const TypeVect* src_vt = TypeVect::make(_src_bt, vector_length()); + assert(VectorNode::is_reinterpret_opcode(scalar_opcode()), "scalar opcode must be reinterpret"); + + Node* in1 = apply_state.transformed_node(in_req(1)); + VectorNode* vn = new VectorReinterpretNode(in1, src_vt, dst_vt); + + register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& apply_state) const { - BoolNode* first = nodes().at(0)->as_Bool(); - uint vlen = nodes().length(); - BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); + const TypeVect* vt = TypeVect::make(element_basic_type(), vector_length()); + assert(scalar_opcode() == Op_Bool, ""); // Cmp + Bool -> VectorMaskCmp - VTransformElementWiseVectorNode* vtn_cmp = in_req(1)->isa_ElementWiseVector(); - assert(vtn_cmp != nullptr && vtn_cmp->nodes().at(0)->is_Cmp(), - "bool vtn expects cmp vtn as input"); + VTransformCmpVectorNode* vtn_cmp = in_req(1)->isa_CmpVector(); + assert(vtn_cmp != nullptr, "bool vtn expects cmp vtn as input"); Node* cmp_in1 = apply_state.transformed_node(vtn_cmp->in_req(1)); Node* cmp_in2 = apply_state.transformed_node(vtn_cmp->in_req(2)); @@ -859,35 +842,30 @@ VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& appl PhaseIdealLoop* phase = apply_state.phase(); ConINode* mask_node = phase->intcon((int)mask); - const TypeVect* vt = TypeVect::make(bt, vlen); VectorNode* vn = new VectorMaskCmpNode(mask, cmp_in1, cmp_in2, mask_node, vt); register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); + return VTransformApplyResult::make_vector(vn); } VTransformApplyResult VTransformReductionVectorNode::apply(VTransformApplyState& apply_state) const { - Node* first = nodes().at(0); - uint vlen = nodes().length(); - int opc = first->Opcode(); - BasicType bt = first->bottom_type()->basic_type(); - Node* init = apply_state.transformed_node(in_req(1)); Node* vec = apply_state.transformed_node(in_req(2)); - ReductionNode* vn = ReductionNode::make(opc, nullptr, init, vec, bt); + ReductionNode* vn = ReductionNode::make(scalar_opcode(), nullptr, init, vec, element_basic_type()); register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->vect_type()->length_in_bytes()); + return VTransformApplyResult::make_vector(vn, vn->vect_type()); } VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& apply_state) const { + int sopc = scalar_opcode(); + uint vlen = vector_length(); + BasicType bt = element_basic_type(); + LoadNode* first = nodes().at(0)->as_Load(); - uint vlen = nodes().length(); - Node* ctrl = first->in(MemNode::Control); + Node* ctrl = apply_state.transformed_node(in_req(MemNode::Control)); + // first has the correct memory state, determined by VTransformGraph::apply_memops_reordering_with_schedule Node* mem = first->in(MemNode::Memory); - Node* adr = first->in(MemNode::Address); - int opc = first->Opcode(); - const TypePtr* adr_type = first->adr_type(); - BasicType bt = apply_state.vloop_analyzer().types().velt_basic_type(first); + Node* adr = apply_state.transformed_node(in_req(MemNode::Address)); // Set the memory dependency of the LoadVector as early as possible. // Walk up the memory chain, and ignore any StoreVector that provably @@ -902,34 +880,33 @@ VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& appl } } - LoadVectorNode* vn = LoadVectorNode::make(opc, ctrl, mem, adr, adr_type, vlen, bt, + LoadVectorNode* vn = LoadVectorNode::make(sopc, ctrl, mem, adr, _adr_type, vlen, bt, control_dependency()); DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); + return VTransformApplyResult::make_vector(vn, vn->vect_type()); } VTransformApplyResult VTransformStoreVectorNode::apply(VTransformApplyState& apply_state) const { + int sopc = scalar_opcode(); + uint vlen = vector_length(); + StoreNode* first = nodes().at(0)->as_Store(); - uint vlen = nodes().length(); - Node* ctrl = first->in(MemNode::Control); + Node* ctrl = apply_state.transformed_node(in_req(MemNode::Control)); + // first has the correct memory state, determined by VTransformGraph::apply_memops_reordering_with_schedule Node* mem = first->in(MemNode::Memory); - Node* adr = first->in(MemNode::Address); - int opc = first->Opcode(); - const TypePtr* adr_type = first->adr_type(); + Node* adr = apply_state.transformed_node(in_req(MemNode::Address)); Node* value = apply_state.transformed_node(in_req(MemNode::ValueIn)); - StoreVectorNode* vn = StoreVectorNode::make(opc, ctrl, mem, adr, adr_type, value, vlen); + StoreVectorNode* vn = StoreVectorNode::make(sopc, ctrl, mem, adr, _adr_type, value, vlen); DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vlen, vn->memory_size()); + return VTransformApplyResult::make_vector(vn, vn->vect_type()); } void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const { PhaseIdealLoop* phase = apply_state.phase(); - Node* first = nodes().at(0); - - register_new_node_from_vectorization(apply_state, vn, first); + register_new_node_from_vectorization(apply_state, vn); for (int i = 0; i < _nodes.length(); i++) { Node* n = _nodes.at(i); @@ -937,9 +914,11 @@ void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scal } } -void VTransformNode::register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn, Node* old_node) const { +void VTransformNode::register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn) const { PhaseIdealLoop* phase = apply_state.phase(); - phase->register_new_node_with_ctrl_of(vn, old_node); + // Using the cl is sometimes not the most accurate, but still correct. We do not have to be + // perfectly accurate, because we will set major_progress anyway. + phase->register_new_node(vn, apply_state.vloop().cl()); phase->igvn()._worklist.push(vn); VectorNode::trace_new_vector(vn, "AutoVectorization"); } @@ -1050,18 +1029,32 @@ void VTransformPopulateIndexNode::print_spec() const { } void VTransformVectorNode::print_spec() const { - tty->print("%d-pack[", _nodes.length()); - for (int i = 0; i < _nodes.length(); i++) { - Node* n = _nodes.at(i); - if (i > 0) { - tty->print(", "); - } - tty->print("%d %s", n->_idx, n->Name()); - } - tty->print("]"); + tty->print("Properties[orig=[%d %s] sopc=%s vlen=%d element_bt=%s]", + approximate_origin()->_idx, + approximate_origin()->Name(), + NodeClassNames[scalar_opcode()], + vector_length(), + type2name(element_basic_type())); if (is_load_or_store_in_loop()) { tty->print(" "); vpointer().print_on(tty, false); } } + +void VTransformElementWiseVectorNode::print_spec() const { + VTransformVectorNode::print_spec(); + tty->print(" vopc=%s", NodeClassNames[_vector_opcode]); +} + +void VTransformReinterpretVectorNode::print_spec() const { + VTransformVectorNode::print_spec(); + tty->print(" src_bt=%s", type2name(_src_bt)); +} + +void VTransformBoolVectorNode::print_spec() const { + VTransformVectorNode::print_spec(); + const BoolTest bt(_test._mask); + tty->print(" test="); + bt.dump_on(tty); +} #endif diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 60b0b5d4f9d..9a4e4de01a2 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -26,6 +26,7 @@ #include "opto/node.hpp" #include "opto/vectorization.hpp" +#include "opto/vectornode.hpp" // VTransform: // - Models the transformation of the scalar loop to vectorized loop: @@ -67,6 +68,7 @@ class VTransformCFGNode; class VTransformOuterNode; class VTransformVectorNode; class VTransformElementWiseVectorNode; +class VTransformCmpVectorNode; class VTransformBoolVectorNode; class VTransformReductionVectorNode; class VTransformMemVectorNode; @@ -90,9 +92,12 @@ public: return VTransformApplyResult(n, 0, 0); } - static VTransformApplyResult make_vector(Node* n, uint vector_length, uint vector_width) { - assert(vector_length > 0 && vector_width > 0, "must have nonzero size"); - return VTransformApplyResult(n, vector_length, vector_width); + static VTransformApplyResult make_vector(VectorNode* vn) { + return VTransformApplyResult(vn, vn->length(), vn->length_in_bytes()); + } + + static VTransformApplyResult make_vector(Node* n, const TypeVect* vt) { + return VTransformApplyResult(n, vt->length(), vt->length_in_bytes()); } static VTransformApplyResult make_empty() { @@ -431,6 +436,7 @@ public: virtual VTransformOuterNode* isa_Outer() { return nullptr; } virtual VTransformVectorNode* isa_Vector() { return nullptr; } virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() { return nullptr; } + virtual VTransformCmpVectorNode* isa_CmpVector() { return nullptr; } virtual VTransformBoolVectorNode* isa_BoolVector() { return nullptr; } virtual VTransformReductionVectorNode* isa_ReductionVector() { return nullptr; } virtual VTransformMemVectorNode* isa_MemVector() { return nullptr; } @@ -445,7 +451,7 @@ public: Node* find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const; - void register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn, Node* old_node) const; + void register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn) const; NOT_PRODUCT(virtual const char* name() const = 0;) NOT_PRODUCT(void print() const;) @@ -590,13 +596,52 @@ public: NOT_PRODUCT(virtual void print_spec() const override;) }; -// Base class for all vector vtnodes. +// Bundle the information needed for vector nodes. +class VTransformVectorNodeProperties : public StackObj { +private: + Node* _approximate_origin; // for proper propagation of node notes + const int _scalar_opcode; + const uint _vector_length; + const BasicType _element_basic_type; + + VTransformVectorNodeProperties(Node* approximate_origin, + int scalar_opcode, + uint vector_length, + BasicType element_basic_type) : + _approximate_origin(approximate_origin), + _scalar_opcode(scalar_opcode), + _vector_length(vector_length), + _element_basic_type(element_basic_type) {} + +public: + static VTransformVectorNodeProperties make_from_pack(const Node_List* pack, const VLoopAnalyzer& vloop_analyzer) { + Node* first = pack->at(0); + int opc = first->Opcode(); + int vlen = pack->size(); + BasicType bt = vloop_analyzer.types().velt_basic_type(first); + return VTransformVectorNodeProperties(first, opc, vlen, bt); + } + + Node* approximate_origin() const { return _approximate_origin; } + int scalar_opcode() const { return _scalar_opcode; } + uint vector_length() const { return _vector_length; } + BasicType element_basic_type() const { return _element_basic_type; } +}; + +// Abstract base class for all vector vtnodes. class VTransformVectorNode : public VTransformNode { private: + const VTransformVectorNodeProperties _properties; +protected: GrowableArray _nodes; public: - VTransformVectorNode(VTransform& vtransform, const uint req, const uint number_of_nodes) : - VTransformNode(vtransform, req), _nodes(vtransform.arena(), number_of_nodes, number_of_nodes, nullptr) {} + VTransformVectorNode(VTransform& vtransform, const uint req, const VTransformVectorNodeProperties properties) : + VTransformNode(vtransform, req), + _properties(properties), + _nodes(vtransform.arena(), + properties.vector_length(), + properties.vector_length(), + nullptr) {} void set_nodes(const Node_List* pack) { for (uint k = 0; k < pack->size(); k++) { @@ -604,20 +649,50 @@ public: } } - const GrowableArray& nodes() const { return _nodes; } virtual VTransformVectorNode* isa_Vector() override { return this; } void register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const; NOT_PRODUCT(virtual void print_spec() const override;) + +protected: + Node* approximate_origin() const { return _properties.approximate_origin(); } + int scalar_opcode() const { return _properties.scalar_opcode(); } + uint vector_length() const { return _properties.vector_length(); } + BasicType element_basic_type() const { return _properties.element_basic_type(); } }; // Catch all for all element-wise vector operations. class VTransformElementWiseVectorNode : public VTransformVectorNode { +private: + const int _vector_opcode; public: - VTransformElementWiseVectorNode(VTransform& vtransform, uint req, uint number_of_nodes) : - VTransformVectorNode(vtransform, req, number_of_nodes) {} + VTransformElementWiseVectorNode(VTransform& vtransform, uint req, const VTransformVectorNodeProperties properties, const int vector_opcode) : + VTransformVectorNode(vtransform, req, properties), _vector_opcode(vector_opcode) {} virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() override { return this; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ElementWiseVector"; };) + NOT_PRODUCT(virtual void print_spec() const override;) +}; + +// The scalar operation was a long -> int operation. +// However, the vector operation is long -> long. +// Hence, we vectorize it as: long --long_op--> long --cast--> int +class VTransformElementWiseLongOpWithCastToIntVectorNode : public VTransformVectorNode { +public: + VTransformElementWiseLongOpWithCastToIntVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : + VTransformVectorNode(vtransform, 2, properties) {} + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ElementWiseLongOpWithCastToIntVector"; };) +}; + +class VTransformReinterpretVectorNode : public VTransformVectorNode { +private: + const BasicType _src_bt; +public: + VTransformReinterpretVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, const BasicType src_bt) : + VTransformVectorNode(vtransform, 2, properties), _src_bt(src_bt) {} + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + NOT_PRODUCT(virtual const char* name() const override { return "ReinterpretVector"; };) + NOT_PRODUCT(virtual void print_spec() const override;) }; struct VTransformBoolTest { @@ -628,23 +703,35 @@ struct VTransformBoolTest { _mask(mask), _is_negated(is_negated) {} }; -class VTransformBoolVectorNode : public VTransformElementWiseVectorNode { +// Cmp + Bool -> VectorMaskCmp +// The Bool node takes care of "apply". +class VTransformCmpVectorNode : public VTransformVectorNode { +public: + VTransformCmpVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : + VTransformVectorNode(vtransform, 3, properties) {} + virtual VTransformCmpVectorNode* isa_CmpVector() override { return this; } + virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override { return VTransformApplyResult::make_empty(); } + NOT_PRODUCT(virtual const char* name() const override { return "CmpVector"; };) +}; + +class VTransformBoolVectorNode : public VTransformVectorNode { private: const VTransformBoolTest _test; public: - VTransformBoolVectorNode(VTransform& vtransform, uint number_of_nodes, VTransformBoolTest test) : - VTransformElementWiseVectorNode(vtransform, 2, number_of_nodes), _test(test) {} + VTransformBoolVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, VTransformBoolTest test) : + VTransformVectorNode(vtransform, 2, properties), _test(test) {} VTransformBoolTest test() const { return _test; } virtual VTransformBoolVectorNode* isa_BoolVector() override { return this; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "BoolVector"; };) + NOT_PRODUCT(virtual void print_spec() const override;) }; class VTransformReductionVectorNode : public VTransformVectorNode { public: // req = 3 -> [ctrl, scalar init, vector] - VTransformReductionVectorNode(VTransform& vtransform, uint number_of_nodes) : - VTransformVectorNode(vtransform, 3, number_of_nodes) {} + VTransformReductionVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties) : + VTransformVectorNode(vtransform, 3, properties) {} virtual VTransformReductionVectorNode* isa_ReductionVector() override { return this; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "ReductionVector"; };) @@ -653,12 +740,16 @@ public: class VTransformMemVectorNode : public VTransformVectorNode { private: const VPointer _vpointer; // with size of the vector +protected: + const TypePtr* _adr_type; public: - VTransformMemVectorNode(VTransform& vtransform, const uint req, uint number_of_nodes, const VPointer& vpointer) : - VTransformVectorNode(vtransform, req, number_of_nodes), - _vpointer(vpointer) {} + VTransformMemVectorNode(VTransform& vtransform, const uint req, const VTransformVectorNodeProperties properties, const VPointer& vpointer, const TypePtr* adr_type) : + VTransformVectorNode(vtransform, req, properties), + _vpointer(vpointer), + _adr_type(adr_type) {} + const GrowableArray& nodes() const { return _nodes; } virtual VTransformMemVectorNode* isa_MemVector() override { return this; } virtual bool is_load_or_store_in_loop() const override { return true; } virtual const VPointer& vpointer() const override { return _vpointer; } @@ -667,8 +758,8 @@ public: class VTransformLoadVectorNode : public VTransformMemVectorNode { public: // req = 3 -> [ctrl, mem, adr] - VTransformLoadVectorNode(VTransform& vtransform, uint number_of_nodes, const VPointer& vpointer) : - VTransformMemVectorNode(vtransform, 3, number_of_nodes, vpointer) {} + VTransformLoadVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, const VPointer& vpointer, const TypePtr* adr_type) : + VTransformMemVectorNode(vtransform, 3, properties, vpointer, adr_type) {} LoadNode::ControlDependency control_dependency() const; virtual VTransformLoadVectorNode* isa_LoadVector() override { return this; } virtual bool is_load_in_loop() const override { return true; } @@ -679,8 +770,8 @@ public: class VTransformStoreVectorNode : public VTransformMemVectorNode { public: // req = 4 -> [ctrl, mem, adr, val] - VTransformStoreVectorNode(VTransform& vtransform, uint number_of_nodes, const VPointer& vpointer) : - VTransformMemVectorNode(vtransform, 4, number_of_nodes, vpointer) {} + VTransformStoreVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, const VPointer& vpointer, const TypePtr* adr_type) : + VTransformMemVectorNode(vtransform, 4, properties, vpointer, adr_type) {} virtual VTransformStoreVectorNode* isa_StoreVector() override { return this; } virtual bool is_load_in_loop() const override { return false; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; @@ -703,8 +794,8 @@ void VTransformGraph::for_each_memop_in_schedule(Callback callback) const { callback(scalar->node()); } - VTransformVectorNode* vector = vtn->isa_Vector(); - if (vector != nullptr && vector->nodes().at(0)->is_Mem()) { + VTransformMemVectorNode* vector = vtn->isa_MemVector(); + if (vector != nullptr) { for (int j = 0; j < vector->nodes().length(); j++) { callback(vector->nodes().at(j)->as_Mem()); } From 2826d1702534783023802ac5c8d8ea575558f09f Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 11 Sep 2025 05:05:30 +0000 Subject: [PATCH 0004/1116] 8367243: Format issues with dist dump debug output in PhaseGVN::dead_loop_check Reviewed-by: thartmann --- src/hotspot/share/opto/phaseX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index a4248cb2b91..00b36d0bf43 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -780,7 +780,7 @@ void PhaseGVN::dead_loop_check( Node *n ) { } } } - if (!no_dead_loop) n->dump_bfs(100,nullptr,"#"); + if (!no_dead_loop) { n->dump_bfs(100, nullptr, ""); } assert(no_dead_loop, "dead loop detected"); } } From 7690a45f77a2da47fa912fe7a2b2faa589f259f0 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Thu, 11 Sep 2025 06:55:32 +0000 Subject: [PATCH 0005/1116] 8366342: Key generator and key pair generator tests skipping, but showing as passed Reviewed-by: weijun --- .../security/pkcs11/KeyGenerator/DESParity.java | 11 ++++++----- .../sun/security/pkcs11/KeyGenerator/TestAES.java | 14 +++++++------- .../security/pkcs11/KeyGenerator/TestChaCha20.java | 7 ++++--- .../pkcs11/KeyGenerator/TestKeyGenerator.java | 2 +- .../pkcs11/KeyPairGenerator/TestDH2048.java | 7 ++++--- .../TestDefaultDHPrivateExpSize.java | 9 ++++----- 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java b/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java index 59f58ca525e..f9da78df0e2 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/DESParity.java @@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ * @run main/othervm DESParity */ +import jtreg.SkippedException; + import java.security.Provider; import java.util.Random; import javax.crypto.SecretKey; @@ -45,8 +47,7 @@ public class DESParity extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("SecretKeyFactory", "DES") == null) { - System.out.println("Not supported by provider, skipping"); - return; + throw new SkippedException("Not supported by provider, skipping"); } Random random = new Random(); SecretKeyFactory kf; @@ -57,7 +58,7 @@ public class DESParity extends PKCS11Test { random.nextBytes(b); SecretKeySpec spec = new SecretKeySpec(b, "DES"); SecretKey key = kf.generateSecret(spec); - if (DESKeySpec.isParityAdjusted(key.getEncoded(), 0) == false) { + if (!DESKeySpec.isParityAdjusted(key.getEncoded(), 0)) { throw new Exception("DES key not parity adjusted"); } } @@ -68,7 +69,7 @@ public class DESParity extends PKCS11Test { random.nextBytes(b); SecretKeySpec spec = new SecretKeySpec(b, "DESede"); SecretKey key = kf.generateSecret(spec); - if (DESedeKeySpec.isParityAdjusted(key.getEncoded(), 0) == false) { + if (!DESedeKeySpec.isParityAdjusted(key.getEncoded(), 0)) { throw new Exception("DESede key not parity adjusted"); } } diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java b/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java index e74007a65e3..66078be30bd 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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,13 +30,14 @@ * @library /test/lib .. * @run main TestAES */ +import jtreg.SkippedException; +import sun.security.util.SecurityProviderConstants; + import java.security.Provider; -import java.security.InvalidAlgorithmParameterException; import java.security.InvalidParameterException; import java.security.NoSuchAlgorithmException; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; -import static sun.security.util.SecurityProviderConstants.*; public class TestAES extends PKCS11Test { @@ -53,17 +54,16 @@ public class TestAES extends PKCS11Test { try { kg = KeyGenerator.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO, nsae); } // first try w/o setting a key length and check if the generated key // length matches SecretKey key = kg.generateKey(); byte[] keyValue = key.getEncoded(); - if (key.getEncoded().length != getDefAESKeySize() >> 3) { + if (key.getEncoded().length != SecurityProviderConstants.getDefAESKeySize() >> 3) { throw new RuntimeException("Default AES key length should be " + - getDefAESKeySize()); + SecurityProviderConstants.getDefAESKeySize()); } for (int keySize : new int[] { 16, 32, 64, 128, 256, 512, 1024 }) { diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java b/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java index a21571cd957..0eaab538655 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ * @library /test/lib .. * @run main/othervm TestChaCha20 */ +import jtreg.SkippedException; + import java.security.Provider; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidParameterException; @@ -54,8 +56,7 @@ public class TestChaCha20 extends PKCS11Test { try { kg = KeyGenerator.getInstance(ALGO, p); } catch (NoSuchAlgorithmException nsae) { - System.out.println("Skip; no support for " + ALGO); - return; + throw new SkippedException("Skip; no support for " + ALGO, nsae); } try { diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java b/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java index 15d0ee87fe4..50886a7aba3 100644 --- a/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/TestKeyGenerator.java @@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java index b05861ff3ae..06a9fa67afe 100644 --- a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java +++ b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, 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 @@ -31,6 +31,8 @@ * @run main/othervm TestDH2048 */ +import jtreg.SkippedException; + import java.security.InvalidParameterException; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -50,8 +52,7 @@ public class TestDH2048 extends PKCS11Test { @Override public void main(Provider p) throws Exception { if (p.getService("KeyPairGenerator", "DH") == null) { - System.out.println("KPG for DH not supported, skipping"); - return; + throw new SkippedException("KPG for DH not supported, skipping"); } KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", p); kpg.initialize(512); diff --git a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java index cb93a96fdd2..3f19a59423b 100644 --- a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java +++ b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultDHPrivateExpSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -21,12 +21,12 @@ * questions. */ -import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Provider; -import java.security.PrivateKey; import javax.crypto.spec.DHParameterSpec; import javax.crypto.interfaces.DHPrivateKey; + +import jtreg.SkippedException; import sun.security.util.SecurityProviderConstants; import sun.security.provider.ParameterCache; @@ -47,8 +47,7 @@ public class TestDefaultDHPrivateExpSize extends PKCS11Test { System.out.println("Testing " + p.getName()); if (p.getService("KeyPairGenerator", "DH") == null) { - System.out.println("Skip, no support for DH KeyPairGenerator"); - return; + throw new SkippedException("Skip, no support for DH KeyPairGenerator"); } KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", p); From 8ba0db0de8b79f64cbfa56683f660f888c880182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Thu, 11 Sep 2025 07:42:39 +0000 Subject: [PATCH 0006/1116] 8366951: Test runtime/logging/StressAsyncUL.java is timing out Reviewed-by: ayang, lkorinth, dholmes, syan --- test/hotspot/jtreg/runtime/logging/StressAsyncUL.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java index 2967507fa64..479f62d6c30 100644 --- a/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java +++ b/test/hotspot/jtreg/runtime/logging/StressAsyncUL.java @@ -45,12 +45,12 @@ public class StressAsyncUL { } } public static void main(String[] args) throws Exception { - analyze_output(false, "-Xlog:async:drop", "-Xlog:all=trace", InnerClass.class.getName()); - analyze_output(true, "-Xlog:async:stall", "-Xlog:all=trace", InnerClass.class.getName()); + analyze_output(false, "-Xlog:async:drop", "-Xlog:all=debug", InnerClass.class.getName()); + analyze_output(true, "-Xlog:async:stall", "-Xlog:all=debug", InnerClass.class.getName()); // Stress test with a very small buffer. Note: Any valid buffer size must be able to hold a flush token. // Therefore the size of the buffer cannot be zero. - analyze_output(false, "-Xlog:async:drop", "-Xlog:all=trace", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); - analyze_output(true, "-Xlog:async:stall", "-Xlog:all=trace", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); + analyze_output(false, "-Xlog:async:drop", "-Xlog:all=debug", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); + analyze_output(true, "-Xlog:async:stall", "-Xlog:all=debug", "-XX:AsyncLogBufferSize=192", InnerClass.class.getName()); } public static class InnerClass { From 0b3a303053d0eb5a98ed3d9df42c659db148b470 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Thu, 11 Sep 2025 08:07:25 +0000 Subject: [PATCH 0007/1116] 8367066: RISC-V: refine register selection in MacroAssembler:: decode_klass_not_null Reviewed-by: fyang, fjiang --- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 13 +++++-------- src/hotspot/cpu/riscv/riscv.ad | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 1436bc02113..8f136135a89 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -3402,6 +3402,8 @@ void MacroAssembler::decode_klass_not_null(Register r, Register tmp) { void MacroAssembler::decode_klass_not_null(Register dst, Register src, Register tmp) { assert(UseCompressedClassPointers, "should only be used for compressed headers"); + assert_different_registers(dst, tmp); + assert_different_registers(src, tmp); if (CompressedKlassPointers::base() == nullptr) { if (CompressedKlassPointers::shift() != 0) { @@ -3412,18 +3414,13 @@ void MacroAssembler::decode_klass_not_null(Register dst, Register src, Register return; } - Register xbase = dst; - if (dst == src) { - xbase = tmp; - } + Register xbase = tmp; - assert_different_registers(src, xbase); mv(xbase, (uintptr_t)CompressedKlassPointers::base()); if (CompressedKlassPointers::shift() != 0) { - Register t = src == dst ? dst : t0; - assert_different_registers(t, xbase); - shadd(dst, src, xbase, t, CompressedKlassPointers::shift()); + // dst = (src << shift) + xbase + shadd(dst, src, xbase, dst /* temporary, dst != xbase */, CompressedKlassPointers::shift()); } else { add(dst, xbase, src); } diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 0c4dd7b71e2..739a525c9a4 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -8938,7 +8938,7 @@ instruct encodeKlass_not_null(iRegNNoSp dst, iRegP src) %{ instruct decodeKlass_not_null(iRegPNoSp dst, iRegN src, iRegPNoSp tmp) %{ match(Set dst (DecodeNKlass src)); - effect(TEMP tmp); + effect(TEMP_DEF dst, TEMP tmp); ins_cost(ALU_COST); format %{ "decode_klass_not_null $dst, $src\t#@decodeKlass_not_null" %} From 3d679087b0376c221d536780cee387dc2dd8019e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Thu, 11 Sep 2025 08:53:09 +0000 Subject: [PATCH 0008/1116] 8367268: Remove unused os::numa_topology_changed() Reviewed-by: ayang, dholmes --- src/hotspot/os/aix/os_aix.cpp | 4 ---- src/hotspot/os/bsd/os_bsd.cpp | 2 -- src/hotspot/os/linux/os_linux.cpp | 2 -- src/hotspot/os/windows/os_windows.cpp | 1 - src/hotspot/share/runtime/os.hpp | 1 - 5 files changed, 10 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index aa119210f47..2dd60b51119 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1753,10 +1753,6 @@ void os::numa_make_global(char *addr, size_t bytes) { void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } -bool os::numa_topology_changed() { - return false; -} - size_t os::numa_get_groups_num() { return 1; } diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 4f5fed2c8c0..8b75c0dcdd8 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1599,8 +1599,6 @@ void os::numa_make_global(char *addr, size_t bytes) { void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } -bool os::numa_topology_changed() { return false; } - size_t os::numa_get_groups_num() { return 1; } diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index d133813feb0..9f896d62d4d 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2988,8 +2988,6 @@ void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { Linux::numa_tonode_memory(addr, bytes, lgrp_hint); } -bool os::numa_topology_changed() { return false; } - size_t os::numa_get_groups_num() { // Return just the number of nodes in which it's possible to allocate memory // (in numa terminology, configured nodes). diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 09d8b542a10..4061ccf9dac 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3794,7 +3794,6 @@ size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { void os::numa_make_global(char *addr, size_t bytes) { } void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } -bool os::numa_topology_changed() { return false; } size_t os::numa_get_groups_num() { return MAX2(numa_node_list_holder.get_count(), 1); } int os::numa_get_group_id() { return 0; } size_t os::numa_get_leaf_groups(uint *ids, size_t size) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 9db4380fc07..4f6830daa4c 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -540,7 +540,6 @@ class os: AllStatic { static void numa_make_global(char *addr, size_t bytes); static size_t numa_get_groups_num(); static size_t numa_get_leaf_groups(uint *ids, size_t size); - static bool numa_topology_changed(); static int numa_get_group_id(); static int numa_get_group_id_for_address(const void* address); static bool numa_get_group_ids_for_range(const void** addresses, int* lgrp_ids, size_t count); From 3355a9d3fa3e57d489f716ebc1c885c1391274ea Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 11 Sep 2025 10:43:25 +0000 Subject: [PATCH 0009/1116] 8285150: Improve tab completion for annotations Reviewed-by: liach --- .../jshell/tool/ConsoleIOContext.java | 19 +- .../jdk/jshell/SourceCodeAnalysisImpl.java | 262 ++++++++++++++++-- .../jdk/jshell/CompletionSuggestionTest.java | 43 +++ .../jdk/jshell/ToolTabSnippetTest.java | 20 ++ 4 files changed, 323 insertions(+), 21 deletions(-) diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java index 5cf301efac5..1662f81710a 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java @@ -394,9 +394,9 @@ class ConsoleIOContext extends IOContext { .reduce(ConsoleIOContext::commonPrefix); String prefix = - prefixOpt.orElse("").substring(cursor - anchor[0]); + prefixOpt.orElse(""); - if (!prefix.isEmpty() && !command) { + if (prefix.length() > cursor - anchor[0] && !command) { //the completion will fill in the prefix, which will invalidate //the documentation, avoid adding documentation tasks into the //todo list: @@ -405,6 +405,7 @@ class ConsoleIOContext extends IOContext { ordinaryCompletion = new OrdinaryCompletionTask(ordinaryCompletionToShow, + anchor[0], prefix, !command && !doc.isEmpty(), hasBoth); @@ -609,15 +610,18 @@ class ConsoleIOContext extends IOContext { private final class OrdinaryCompletionTask implements CompletionTask { private final List toShow; + private final int anchor; private final String prefix; private final boolean cont; private final boolean showSmart; public OrdinaryCompletionTask(List toShow, + int anchor, String prefix, boolean cont, boolean showSmart) { this.toShow = toShow; + this.anchor = anchor; this.prefix = prefix; this.cont = cont; this.showSmart = showSmart; @@ -630,7 +634,14 @@ class ConsoleIOContext extends IOContext { @Override public Result perform(String text, int cursor) throws IOException { - in.putString(prefix); + String existingPrefix = in.getBuffer().substring(anchor, cursor); + + if (prefix.startsWith(existingPrefix)) { + in.putString(prefix.substring(existingPrefix.length())); + } else { + in.getBuffer().backspace(existingPrefix.length()); + in.putString(prefix); + } boolean showItems = toShow.size() > 1 || showSmart; @@ -639,7 +650,7 @@ class ConsoleIOContext extends IOContext { printColumns(toShow); } - if (!prefix.isEmpty()) + if (prefix.length() > existingPrefix.length()) return showItems ? Result.FINISH : Result.SKIP_NOREPAINT; return cont ? Result.CONTINUE : Result.FINISH; diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index fffdfd5b33c..045734d9f55 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -38,6 +38,7 @@ import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.MethodTree; import com.sun.source.tree.ModifiersTree; +import com.sun.source.tree.NewArrayTree; import com.sun.source.tree.NewClassTree; import com.sun.source.tree.Scope; import com.sun.source.tree.Tree; @@ -111,6 +112,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -310,13 +312,19 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { default -> proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); }; String[] requiredPrefix = new String[] {identifier}; - return computeSuggestions(codeWrap, cursor, requiredPrefix, anchor).stream() - .filter(s -> s.continuation().startsWith(requiredPrefix[0]) && !s.continuation().equals(REPL_DOESNOTMATTER_CLASS_NAME)) + return computeSuggestions(codeWrap, code, cursor, requiredPrefix, anchor).stream() + .filter(s -> filteringText(s).startsWith(requiredPrefix[0]) && !s.continuation().equals(REPL_DOESNOTMATTER_CLASS_NAME)) .sorted(Comparator.comparing(Suggestion::continuation)) .toList(); } - private List computeSuggestions(OuterWrap code, int cursor, String[] requiredPrefix, int[] anchor) { + private static String filteringText(Suggestion suggestion) { + return suggestion instanceof SuggestionImpl impl + ? impl.filteringText + : suggestion.continuation(); + } + + private List computeSuggestions(OuterWrap code, String inputCode, int cursor, String[] requiredPrefix, int[] anchor) { return proc.taskFactory.analyze(code, at -> { SourcePositions sp = at.trees().getSourcePositions(); CompilationUnitTree topLevel = at.firstCuTree(); @@ -479,6 +487,19 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { addScopeElements(at, scope, IDENTITY, accept, IS_PACKAGE.negate().and(smartTypeFilter), result); break; } + if (isAnnotation(tp)) { + if (getAnnotationAttributeNameOrNull(tp.getParentPath(), true) != null) { + //nested annotation + result = completionSuggestionsImpl(inputCode, cursor - 1, anchor); + requiredPrefix[0] = "@" + requiredPrefix[0]; + return result; + } + + Predicate accept = accessibility.and(STATIC_ONLY) + .and(IS_PACKAGE.or(IS_CLASS).or(IS_INTERFACE)); + addScopeElements(at, scope, IDENTITY, accept, IS_PACKAGE.negate().and(smartTypeFilter), result); + break; + } ImportTree it = findImport(tp); if (it != null) { if (it.isModule()) { @@ -512,6 +533,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { case ERRONEOUS: { boolean staticOnly = ReplResolve.isStatic(((JavacScope)scope).getEnv()); Predicate accept = accessibility.and(staticOnly ? STATIC_ONLY : TRUE); + boolean insertPrimitiveTypes = true; if (isClass(tp)) { ClassTree clazz = (ClassTree) tp.getParentPath().getLeaf(); if (clazz.getExtendsClause() == tp.getLeaf()) { @@ -539,20 +561,101 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { if (var.getType() == tp.getLeaf()) { accept = accept.and(IS_TYPE); } + } else if (tp.getParentPath().getLeaf().getKind() == Kind.ANNOTATION) { + AnnotationTree annotation = (AnnotationTree) tp.getParentPath().getLeaf(); + Element annotationType = at.trees().getElement(tp.getParentPath()); + Set present = annotation.getArguments() + .stream() + .filter(expr -> expr.getKind() == Kind.ASSIGNMENT) + .map(expr -> (AssignmentTree) expr) + .map(assign -> assign.getVariable()) + .filter(var -> var.getKind() == Kind.IDENTIFIER) + .map(var -> ((IdentifierTree) var).getName().toString()) + .collect(Collectors.toSet()); + addElements(ElementFilter.methodsIn(annotationType.getEnclosedElements()), el -> !present.contains(el.getSimpleName().toString()), TRUE, _ -> " = ", result); + break; + } else if (getAnnotationAttributeNameOrNull(tp, true) instanceof String attributeName) { + Element annotationType = tp.getParentPath().getParentPath().getLeaf().getKind() == Kind.ANNOTATION + ? at.trees().getElement(tp.getParentPath().getParentPath()) + : at.trees().getElement(tp.getParentPath().getParentPath().getParentPath()); + if (sp.getEndPosition(topLevel, tp.getParentPath().getLeaf()) == (-1)) { + //synthetic 'value': + addElements(ElementFilter.methodsIn(annotationType.getEnclosedElements()), TRUE, TRUE, _ -> " = ", result); + boolean hasValue = findAnnotationAttributeIfAny(annotationType, "value").isPresent(); + if (!hasValue) { + break; + } + } + Optional ee = findAnnotationAttributeIfAny(annotationType, attributeName); + if (ee.isEmpty()) { + break; + } + TypeMirror relevantAttributeType = ee.orElseThrow().getReturnType(); + if (relevantAttributeType.getKind() == TypeKind.ARRAY) { + relevantAttributeType = ((ArrayType) relevantAttributeType).getComponentType(); + } + if (relevantAttributeType.getKind() == TypeKind.DECLARED && + at.getTypes().asElement(relevantAttributeType) instanceof Element attributeTypeEl) { + if (attributeTypeEl.getKind() == ElementKind.ANNOTATION_TYPE) { + boolean hasAnyAttributes = + ElementFilter.methodsIn(attributeTypeEl.getEnclosedElements()) + .stream() + .anyMatch(attribute -> attribute.getParameters().isEmpty()); + String paren = hasAnyAttributes ? "(" : ""; + String name = scopeContent(at, scope, IDENTITY).contains(attributeTypeEl) + ? attributeTypeEl.getSimpleName().toString() //simple name ought to be enough: + : ((TypeElement) attributeTypeEl).getQualifiedName().toString(); + result.add(new SuggestionImpl("@" + name + paren, true)); + break; + } else if (attributeTypeEl.getKind() == ElementKind.ENUM) { + String typeName = scopeContent(at, scope, IDENTITY).contains(attributeTypeEl) + ? attributeTypeEl.getSimpleName().toString() //simple name ought to be enough: + : ((TypeElement) attributeTypeEl).getQualifiedName().toString(); + result.add(new SuggestionImpl(typeName, true)); + result.addAll(ElementFilter.fieldsIn(attributeTypeEl.getEnclosedElements()) + .stream() + .filter(e -> e.getKind() == ElementKind.ENUM_CONSTANT) + .map(c -> new SuggestionImpl(scopeContent(at, scope, IDENTITY).contains(c) + ? c.getSimpleName().toString() + : typeName + "." + c.getSimpleName(), c.getSimpleName().toString(), + true)) + .toList()); + break; + } + } + accept = accessibility.and(el -> { + return switch (el.getKind()) { + case PACKAGE, ANNOTATION_TYPE, ENUM, INTERFACE, RECORD, ENUM_CONSTANT -> true; + case CLASS -> !((TypeElement) el).asType().getKind().isPrimitive(); + case FIELD -> isPermittedAnnotationAttributeFieldType(at, el.asType()); + default -> false; + }; + }); + insertPrimitiveTypes = false; } addScopeElements(at, scope, IDENTITY, accept, smartFilter, result); - Tree parent = tp.getParentPath().getLeaf(); - accept = switch (parent.getKind()) { - case VARIABLE -> ((VariableTree) parent).getType() == tp.getLeaf() ? - IS_VOID.negate() : - TRUE; - case PARAMETERIZED_TYPE -> FALSE; // TODO: JEP 218: Generics over Primitive Types - case TYPE_PARAMETER, CLASS, INTERFACE, ENUM, RECORD -> FALSE; - default -> TRUE; - }; - addElements(primitivesOrVoid(at), accept, smartFilter, result); + if (insertPrimitiveTypes) { + Tree parent = tp.getParentPath().getLeaf(); + accept = switch (parent.getKind()) { + case VARIABLE -> ((VariableTree) parent).getType() == tp.getLeaf() ? + IS_VOID.negate() : + TRUE; + case PARAMETERIZED_TYPE -> FALSE; // TODO: JEP 218: Generics over Primitive Types + case TYPE_PARAMETER, CLASS, INTERFACE, ENUM, RECORD -> FALSE; + default -> TRUE; + }; + addElements(primitivesOrVoid(at), accept, smartFilter, result); + } + + boolean hasBooleanSmartType = targetTypes != null && + StreamSupport.stream(targetTypes.spliterator(), false) + .anyMatch(tm -> tm.getKind() == TypeKind.BOOLEAN); + if (hasBooleanSmartType) { + result.add(new SuggestionImpl("true", true)); + result.add(new SuggestionImpl("false", true)); + } break; } } @@ -917,6 +1020,12 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { long start = sp.getStartPosition(topLevel, tree); long end = sp.getEndPosition(topLevel, tree); + if (end == (-1) && tree.getKind() == Kind.ASSIGNMENT && + getCurrentPath() != null && + getCurrentPath().getLeaf().getKind() == Kind.ANNOTATION) { + //the assignment is synthetically generated, take the end pos of the nested tree: + end = sp.getEndPosition(topLevel, ((AssignmentTree) tree).getExpression()); + } if (start <= wrapEndPos && wrapEndPos <= end && (deepest[0] == null || deepest[0].getLeaf() == getCurrentPath().getLeaf())) { deepest[0] = new TreePath(getCurrentPath(), tree); @@ -946,6 +1055,12 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { ((MethodTree)parent).getThrows().contains(tp.getLeaf()); } + private boolean isAnnotation(TreePath tp) { + Tree parent = tp.getParentPath().getLeaf(); + return parent.getKind() == Kind.ANNOTATION && + ((AnnotationTree)parent).getAnnotationType().equals(tp.getLeaf()); + } + private boolean isClass(TreePath tp) { return tp.getParentPath() != null && CLASS_KINDS.contains(tp.getParentPath().getLeaf().getKind()); @@ -961,6 +1076,39 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { tp.getParentPath().getLeaf().getKind() == Kind.VARIABLE; } + private String getAnnotationAttributeNameOrNull(TreePath tp, boolean acceptArray) { + if (tp.getParentPath() == null) { + return null; + } + if (tp.getParentPath().getLeaf().getKind() == Kind.NEW_ARRAY && + ((NewArrayTree) tp.getParentPath().getLeaf()).getInitializers().contains(tp.getLeaf())) { + if (acceptArray) { + return getAnnotationAttributeNameOrNull(tp.getParentPath(), false); + } else { + return null; + } + } + if (tp.getParentPath().getParentPath() == null || + tp.getParentPath().getLeaf().getKind() != Kind.ASSIGNMENT || + tp.getParentPath().getParentPath().getLeaf().getKind() != Kind.ANNOTATION) { + return null; + } + AssignmentTree assign = (AssignmentTree) tp.getParentPath().getLeaf(); + if (assign.getVariable().getKind() != Kind.IDENTIFIER) { + return null; + } + return ((IdentifierTree) assign.getVariable()).getName().toString(); + } + + private Optional findAnnotationAttributeIfAny(Element annotationType, + String attributeName) { + return ElementFilter.methodsIn(annotationType.getEnclosedElements()) + .stream() + .filter(ee -> ee.getSimpleName().contentEquals(attributeName)) + .filter(ee -> ee.getParameters().isEmpty()) + .findAny(); + } + private ImportTree findImport(TreePath tp) { while (tp != null && tp.getLeaf().getKind() != Kind.IMPORT) { tp = tp.getParentPath(); @@ -987,6 +1135,17 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { }; } + private boolean isPermittedAnnotationAttributeFieldType(AnalyzeTask at, TypeMirror type) { + if (type.getKind().isPrimitive()) { + return true; + } + if (type.getKind() == TypeKind.DECLARED) { + Element el = ((DeclaredType) type).asElement(); + return el.getKind() == ElementKind.ENUM || el.equals(at.getElements().getTypeElement("java.lang.String")); + } + return false; + } + private final Predicate TRUE = el -> true; private final Predicate FALSE = TRUE.negate(); private final Predicate IS_STATIC = el -> el.getModifiers().contains(Modifier.STATIC); @@ -1237,7 +1396,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { return new VarSymbol(Flags.PUBLIC | Flags.STATIC | Flags.FINAL, _class, classType, erasedSite.tsym); } - private Iterable scopeContent(AnalyzeTask at, Scope scope, Function> elementConvertor) { + private Collection scopeContent(AnalyzeTask at, Scope scope, Function> elementConvertor) { Iterable scopeIterable = () -> new Iterator() { private Scope currentScope = scope; @Override @@ -1306,11 +1465,54 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { Tree current = forPath.getLeaf(); + if (current.getKind() == Kind.ANNOTATION) { + Element type = at.trees().getElement(forPath); + if (type != null) { + Optional valueAttr = + ElementFilter.methodsIn(type.getEnclosedElements()) + .stream() + .filter(ee -> ee.getSimpleName().contentEquals("value")) + .findAny(); + if (valueAttr.isPresent()) { + TypeMirror returnType = valueAttr.orElseThrow().getReturnType(); + + if (returnType.getKind() == TypeKind.ARRAY) { + returnType = ((ArrayType) returnType).getComponentType(); + } + + return Collections.singletonList(returnType); + } + } + } + switch (forPath.getParentPath().getLeaf().getKind()) { + case NEW_ARRAY: + if (getAnnotationAttributeNameOrNull(forPath, true) != null) { + forPath = forPath.getParentPath(); + current = forPath.getLeaf(); + //fall-through + } else { + break; + } case ASSIGNMENT: { AssignmentTree tree = (AssignmentTree) forPath.getParentPath().getLeaf(); - if (tree.getExpression() == current) - return Collections.singletonList(at.trees().getTypeMirror(new TreePath(forPath.getParentPath(), tree.getVariable()))); + if (tree.getExpression() == current) { + if (forPath.getParentPath().getParentPath().getLeaf().getKind() == Kind.ANNOTATION) { + Element method = at.trees().getElement(new TreePath(forPath.getParentPath(), tree.getVariable())); + if (method != null && method.getKind() == ElementKind.METHOD) { + TypeMirror returnType = ((ExecutableElement) method).getReturnType(); + + if (returnType.getKind() == TypeKind.ARRAY) { + returnType = ((ArrayType) returnType).getComponentType(); + } + + return Collections.singletonList(returnType); + } + return null; + } else { + return Collections.singletonList(at.trees().getTypeMirror(new TreePath(forPath.getParentPath(), tree.getVariable()))); + } + } break; } case VARIABLE: { @@ -1558,7 +1760,8 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { TreePath prevPath = null; while (tp != null && tp.getLeaf().getKind() != Kind.METHOD_INVOCATION && tp.getLeaf().getKind() != Kind.NEW_CLASS && tp.getLeaf().getKind() != Kind.IDENTIFIER && - tp.getLeaf().getKind() != Kind.MEMBER_SELECT) { + tp.getLeaf().getKind() != Kind.MEMBER_SELECT && + tp.getLeaf().getKind() != Kind.ANNOTATION) { prevPath = tp; tp = tp.getParentPath(); } @@ -1611,6 +1814,18 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } elements = Stream.of(el); + } else if (tp.getLeaf().getKind() == Kind.ANNOTATION) { + Element el = at.trees().getElement(tp); + + if (el == null || + el.getKind() != ElementKind.ANNOTATION_TYPE) { + //erroneous state: + return Collections.emptyList(); + } + + elements = ElementFilter.methodsIn(el.getEnclosedElements()) + .stream() + .map(ee -> (Element) ee); } else { return Collections.emptyList(); } @@ -2220,6 +2435,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { private static class SuggestionImpl implements Suggestion { private final String continuation; + private final String filteringText; private final boolean matchesType; /** @@ -2229,7 +2445,19 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { * @param matchesType does the candidate match the target type */ public SuggestionImpl(String continuation, boolean matchesType) { + this(continuation, continuation, matchesType); + } + + /** + * Create a {@code Suggestion} instance. + * + * @param continuation a candidate continuation of the user's input + * @param filteringText a text that should be used for filtering + * @param matchesType does the candidate match the target type + */ + public SuggestionImpl(String continuation, String filteringText, boolean matchesType) { this.continuation = continuation; + this.filteringText = filteringText; this.matchesType = matchesType; } diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index a710f60aec4..19f7b89a1b3 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -898,4 +898,47 @@ public class CompletionSuggestionTest extends KullaTesting { assertCompletion("p1.|", "p2.", "p3."); } + + @Test + public void testAnnotation() { + assertCompletion("@Deprec|", "Deprecated"); + assertCompletion("@Deprecated(|", "forRemoval = ", "since = "); + assertCompletion("@Deprecated(forRemoval = |", true, "false", "true"); + assertCompletion("@Deprecated(forRemoval = true, |", "since = "); + assertEval("import java.lang.constant.ConstantDescs;"); + assertEval("import static java.lang.constant.ConstantDescs.*;"); + assertEval("@interface Ann1 { public String test(); }"); + assertCompletionIncludesExcludes("@Ann1(test = |", Set.of("java.", "ConstantDescs", "INIT_NAME"), Set.of("CD_char", "byte")); + assertEval("@interface Ann2 { public String[] test(); }"); + assertCompletionIncludesExcludes("@Ann2(test = {|", Set.of("java.", "ConstantDescs", "INIT_NAME"), Set.of("CD_char", "byte")); + assertCompletionIncludesExcludes("@Ann2(test = {|", true, Set.of("INIT_NAME"), Set.of("java.", "ConstantDescs", "CD_char", "byte")); + assertEval("@interface Ann3 { public String value(); }"); + assertCompletionIncludesExcludes("@Ann3(|", Set.of("java.", "ConstantDescs", "INIT_NAME", "value = "), Set.of("CD_char", "byte")); + assertCompletionIncludesExcludes("@Ann3(|", true, Set.of("INIT_NAME", "value = "), Set.of("java.", "ConstantDescs", "CD_char", "byte")); + assertSignature("@Deprecated(|", "boolean Deprecated.forRemoval()", "String Deprecated.since()"); + assertEval("@interface Ann4 { public String[] value(); }"); + assertCompletionIncludesExcludes("@Ann4({|", Set.of("java.", "ConstantDescs", "INIT_NAME"), Set.of("value = ")); + assertEval("@interface Ann5 { public Ann4[] value(); }"); + assertCompletion("@Ann5(|", true, "@Ann4(", "value = "); + assertCompletion("@Ann5({|", true, "@Ann4("); + assertCompletion("@Ann5(|", false); + assertCompletion("@Ann5({|", false); + assertCompletion("@Ann5(@|", true, "@Ann4("); + assertCompletion("@Ann5(v|", true, "value = "); + assertEval("@interface Ann6 { public java.lang.annotation.Retention[] value(); }"); + assertCompletion("@Ann6(|", true, "@java.lang.annotation.Retention(", "value = "); + assertEval("@interface Ann7 { }"); //no attributes + assertEval("@interface Ann8 { public Ann7[] value(); }"); + assertCompletion("@Ann8(|", true, "@Ann7", "value = "); + assertEval("enum En { AA, BB, EE; }"); + assertEval("@interface Ann9 { public En[] value(); }"); + assertCompletion("@Ann9(|", true, "En", "En.AA", "En.BB", "En.EE", "value = "); + assertCompletion("@Ann9(A|", true, "En.AA"); + assertCompletion("@Ann9(E|", true, "En", "En.EE"); + assertCompletionIncludesExcludes("@Ann9(En.|", Set.of("AA", "BB", "EE"), Set.of()); + assertEval("@interface AnnA { public java.lang.annotation.RetentionPolicy[] value(); }"); + assertCompletion("@AnnA(C|", true, "java.lang.annotation.RetentionPolicy.CLASS"); + assertEval("import static java.lang.annotation.RetentionPolicy.*;"); + assertCompletion("@AnnA(C|", true, "CLASS"); + } } diff --git a/test/langtools/jdk/jshell/ToolTabSnippetTest.java b/test/langtools/jdk/jshell/ToolTabSnippetTest.java index 39189da8686..968935b0814 100644 --- a/test/langtools/jdk/jshell/ToolTabSnippetTest.java +++ b/test/langtools/jdk/jshell/ToolTabSnippetTest.java @@ -344,4 +344,24 @@ public class ToolTabSnippetTest extends UITesting { waitOutput(out, PROMPT + "new InstantiationE"); }); } + + @Test + public void testAnnotation() throws Exception { + doRunTest((inputSink, out) -> { + inputSink.write("@interface Ann1 { public java.lang.annotation.Retention[] value(); }\n"); + waitOutput(out, "\n\\u001B\\[\\?2004h" + PROMPT); + + //-> + inputSink.write("@Ann1(" + TAB); + waitOutput(out, ".*@java.lang.annotation.Retention\\(.*value =.*" + + REDRAW_PROMPT + "@Ann1\\("); + inputSink.write("@" + TAB); + waitOutput(out, "^@java.lang.annotation.Retention\\("); + inputSink.write(TAB); + waitOutput(out, ".*java.lang.annotation.RetentionPolicy.*java.lang.annotation.RetentionPolicy.CLASS.*" + + REDRAW_PROMPT + "@Ann1\\(@java.lang.annotation.Retention\\("); + inputSink.write("CL" + TAB); + waitOutput(out, "CL\\u001B\\[2Djava.lang.annotation.RetentionPolicy.CLASS \\u0008"); + }); + } } From 063f970f0f5e851d72dad0112735692761d6ba36 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 11 Sep 2025 11:22:12 +0000 Subject: [PATCH 0010/1116] 8367401: Parallel: Remove unused field in PSKeepAliveClosure Reviewed-by: stefank, fandreuzzi --- src/hotspot/share/gc/parallel/psScavenge.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 3a47d5864f3..ced84061ec5 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -148,15 +148,10 @@ public: PSIsAliveClosure PSScavenge::_is_alive_closure; class PSKeepAliveClosure: public OopClosure { -protected: - MutableSpace* _to_space; PSPromotionManager* _promotion_manager; public: PSKeepAliveClosure(PSPromotionManager* pm) : _promotion_manager(pm) { - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - _to_space = heap->young_gen()->to_space(); - assert(_promotion_manager != nullptr, "Sanity"); } From a2d272a02a079e2413d10ad2decb04681ce2f961 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 11 Sep 2025 11:22:29 +0000 Subject: [PATCH 0011/1116] 8367339: Parallel: Remove PSScavenge::should_scavenge Reviewed-by: tschatzl, fandreuzzi --- src/hotspot/share/gc/parallel/psCardTable.cpp | 1 - .../share/gc/parallel/psClosure.inline.hpp | 16 ++--- .../share/gc/parallel/psPromotionManager.cpp | 11 +--- .../share/gc/parallel/psPromotionManager.hpp | 3 - .../gc/parallel/psPromotionManager.inline.hpp | 8 +-- src/hotspot/share/gc/parallel/psScavenge.cpp | 2 +- src/hotspot/share/gc/parallel/psScavenge.hpp | 9 --- .../share/gc/parallel/psScavenge.inline.hpp | 63 ------------------- 8 files changed, 13 insertions(+), 100 deletions(-) delete mode 100644 src/hotspot/share/gc/parallel/psScavenge.inline.hpp diff --git a/src/hotspot/share/gc/parallel/psCardTable.cpp b/src/hotspot/share/gc/parallel/psCardTable.cpp index 22a38d816f6..3c40726b721 100644 --- a/src/hotspot/share/gc/parallel/psCardTable.cpp +++ b/src/hotspot/share/gc/parallel/psCardTable.cpp @@ -26,7 +26,6 @@ #include "gc/parallel/parallelScavengeHeap.inline.hpp" #include "gc/parallel/psCardTable.hpp" #include "gc/parallel/psPromotionManager.inline.hpp" -#include "gc/parallel/psScavenge.inline.hpp" #include "gc/parallel/psYoungGen.hpp" #include "memory/iterator.inline.hpp" #include "oops/access.inline.hpp" diff --git a/src/hotspot/share/gc/parallel/psClosure.inline.hpp b/src/hotspot/share/gc/parallel/psClosure.inline.hpp index 914a16e77a6..825612d598a 100644 --- a/src/hotspot/share/gc/parallel/psClosure.inline.hpp +++ b/src/hotspot/share/gc/parallel/psClosure.inline.hpp @@ -28,7 +28,7 @@ // No psClosure.hpp #include "gc/parallel/psPromotionManager.inline.hpp" -#include "gc/parallel/psScavenge.inline.hpp" +#include "gc/parallel/psScavenge.hpp" #include "memory/iterator.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" @@ -39,8 +39,9 @@ public: virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } virtual void do_oop(oop* p) { - if (PSScavenge::should_scavenge(p)) { - oop o = RawAccess::oop_load(p); + oop o = RawAccess<>::oop_load(p); + if (PSScavenge::is_obj_in_young(o)) { + assert(!PSScavenge::is_obj_in_to_space(o), "Revisiting roots?"); assert(o->is_forwarded(), "Objects are already forwarded before weak processing"); oop new_obj = o->forwardee(); if (log_develop_is_enabled(Trace, gc, scavenge)) { @@ -89,12 +90,11 @@ public: void do_oop(narrowOop* p) { ShouldNotReachHere(); } void do_oop(oop* p) { - ParallelScavengeHeap* psh = ParallelScavengeHeap::heap(); - assert(!psh->is_in_reserved(p), "GC barrier needed"); - if (PSScavenge::should_scavenge(p)) { - assert(PSScavenge::should_scavenge(p, true), "revisiting object?"); + assert(!ParallelScavengeHeap::heap()->is_in_reserved(p), "GC barrier needed"); - oop o = RawAccess::oop_load(p); + oop o = RawAccess<>::oop_load(p); + if (PSScavenge::is_obj_in_young(o)) { + assert(!PSScavenge::is_obj_in_to_space(o), "Revisiting roots?"); oop new_obj = _pm->copy_to_survivor_space(o); RawAccess::oop_store(p, new_obj); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.cpp b/src/hotspot/share/gc/parallel/psPromotionManager.cpp index 0a463ab7516..90914d87ba4 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp @@ -27,7 +27,7 @@ #include "gc/parallel/parallelScavengeHeap.hpp" #include "gc/parallel/psOldGen.hpp" #include "gc/parallel/psPromotionManager.inline.hpp" -#include "gc/parallel/psScavenge.inline.hpp" +#include "gc/parallel/psScavenge.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/partialArraySplitter.inline.hpp" @@ -86,15 +86,6 @@ void PSPromotionManager::initialize() { } } -// Helper functions to get around the circular dependency between -// psScavenge.inline.hpp and psPromotionManager.inline.hpp. -bool PSPromotionManager::should_scavenge(oop* p, bool check_to_space) { - return PSScavenge::should_scavenge(p, check_to_space); -} -bool PSPromotionManager::should_scavenge(narrowOop* p, bool check_to_space) { - return PSScavenge::should_scavenge(p, check_to_space); -} - PSPromotionManager* PSPromotionManager::gc_thread_promotion_manager(uint index) { assert(index < ParallelGCThreads, "index out of range"); assert(_manager_array != nullptr, "Sanity"); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index f1169c8ad63..20fe3c74a46 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -167,9 +167,6 @@ class PSPromotionManager { inline void process_popped_location_depth(ScannerTask task, bool stolen); - static bool should_scavenge(oop* p, bool check_to_space = false); - static bool should_scavenge(narrowOop* p, bool check_to_space = false); - template void copy_and_push_safe_barrier(T* p); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 6154abf1b1c..31c1c445a32 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -31,7 +31,7 @@ #include "gc/parallel/parMarkBitMap.inline.hpp" #include "gc/parallel/psOldGen.hpp" #include "gc/parallel/psPromotionLAB.inline.hpp" -#include "gc/parallel/psScavenge.inline.hpp" +#include "gc/parallel/psScavenge.hpp" #include "gc/parallel/psStringDedup.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shared/taskqueue.inline.hpp" @@ -139,7 +139,8 @@ inline void PSPromotionManager::push_contents_bounded(oop obj, HeapWord* left, H template inline oop PSPromotionManager::copy_to_survivor_space(oop o) { - assert(should_scavenge(&o), "Sanity"); + assert(PSScavenge::is_obj_in_young(o), "precondition"); + assert(!PSScavenge::is_obj_in_to_space(o), "precondition"); // NOTE! We must be very careful with any methods that access the mark // in o. There may be multiple threads racing on it, and it may be forwarded @@ -235,8 +236,6 @@ inline HeapWord* PSPromotionManager::allocate_in_old_gen(Klass* klass, template inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, markWord test_mark) { - assert(should_scavenge(&o), "Sanity"); - oop new_obj = nullptr; bool new_obj_is_tenured = false; @@ -334,7 +333,6 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, template inline void PSPromotionManager::copy_and_push_safe_barrier(T* p) { assert(ParallelScavengeHeap::heap()->is_in_reserved(p), "precondition"); - assert(should_scavenge(p, true), "revisiting object?"); oop o = RawAccess::oop_load(p); oop new_obj = copy_to_survivor_space(o); diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index ced84061ec5..62d382b40f0 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -33,7 +33,7 @@ #include "gc/parallel/psParallelCompact.inline.hpp" #include "gc/parallel/psPromotionManager.inline.hpp" #include "gc/parallel/psRootType.hpp" -#include "gc/parallel/psScavenge.inline.hpp" +#include "gc/parallel/psScavenge.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcId.hpp" diff --git a/src/hotspot/share/gc/parallel/psScavenge.hpp b/src/hotspot/share/gc/parallel/psScavenge.hpp index 8da555a8bb4..c297a46a46e 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.hpp +++ b/src/hotspot/share/gc/parallel/psScavenge.hpp @@ -100,15 +100,6 @@ class PSScavenge: AllStatic { // Return true iff a young-gc is completed without promotion-failure. static bool invoke(bool clear_soft_refs); - template static inline bool should_scavenge(T* p); - - // These call should_scavenge() above and, if it returns true, also check that - // the object was not newly copied into to_space. The version with the bool - // argument is a convenience wrapper that fetches the to_space pointer from - // the heap and calls the other version (if the arg is true). - template static inline bool should_scavenge(T* p, MutableSpace* to_space); - template static inline bool should_scavenge(T* p, bool check_to_space); - // Is an object in the young generation // This assumes that the 'o' is in the heap, // so it only checks one side of the complete predicate. diff --git a/src/hotspot/share/gc/parallel/psScavenge.inline.hpp b/src/hotspot/share/gc/parallel/psScavenge.inline.hpp deleted file mode 100644 index af3ff4c6165..00000000000 --- a/src/hotspot/share/gc/parallel/psScavenge.inline.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2002, 2019, 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_GC_PARALLEL_PSSCAVENGE_INLINE_HPP -#define SHARE_GC_PARALLEL_PSSCAVENGE_INLINE_HPP - -#include "gc/parallel/psScavenge.hpp" - -#include "gc/parallel/parallelScavengeHeap.hpp" -#include "logging/log.hpp" -#include "memory/iterator.hpp" -#include "memory/resourceArea.hpp" -#include "oops/access.inline.hpp" -#include "oops/oop.inline.hpp" -#include "utilities/globalDefinitions.hpp" - -template inline bool PSScavenge::should_scavenge(T* p) { - T heap_oop = RawAccess<>::oop_load(p); - return PSScavenge::is_obj_in_young(heap_oop); -} - -template -inline bool PSScavenge::should_scavenge(T* p, MutableSpace* to_space) { - if (should_scavenge(p)) { - oop obj = RawAccess::oop_load(p); - // Skip objects copied to to_space since the scavenge started. - HeapWord* const addr = cast_from_oop(obj); - return addr < to_space->bottom() || addr >= to_space->end(); - } - return false; -} - -template -inline bool PSScavenge::should_scavenge(T* p, bool check_to_space) { - if (check_to_space) { - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - return should_scavenge(p, heap->young_gen()->to_space()); - } - return should_scavenge(p); -} - -#endif // SHARE_GC_PARALLEL_PSSCAVENGE_INLINE_HPP From 56f2f7a3af0574357d5d3f99dcd908721ac710e9 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Thu, 11 Sep 2025 13:22:20 +0000 Subject: [PATCH 0012/1116] 8367138: JNI exception pending in os_getCmdlineAndUserInfo of ProcessHandleImpl_macosx.c Reviewed-by: bpb, naoto, jpai, lancea --- src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c b/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c index 9e1d092c57d..2db64ef37b5 100644 --- a/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c +++ b/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c @@ -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 @@ -263,6 +263,7 @@ void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) { // on other platforms like Linux/Solaris/AIX where the uid comes from the // same source like the command line info. unix_getUserInfo(env, jinfo, getUID(pid)); + JNU_CHECK_EXCEPTION(env); // Get the maximum size of the arguments mib[0] = CTL_KERN; From 4ea8979b93f80e9ecbc197ee12ceb523ef8da6aa Mon Sep 17 00:00:00 2001 From: Artur Barashev Date: Thu, 11 Sep 2025 13:53:08 +0000 Subject: [PATCH 0013/1116] 8365953: Key manager returns no certificates when handshakeSession is not an ExtendedSSLSession Reviewed-by: djelinski, wetmore --- .../ssl/X509KeyManagerCertChecking.java | 47 +- .../AlgorithmConstraintsCheck.java | 28 +- ...xtendedSSLSessionAlgorithmConstraints.java | 405 ++++++++++++++++++ 3 files changed, 436 insertions(+), 44 deletions(-) create mode 100644 test/jdk/sun/security/ssl/X509KeyManager/NonExtendedSSLSessionAlgorithmConstraints.java diff --git a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java index 00a7ae84352..6f18b80395a 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java +++ b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerCertChecking.java @@ -167,25 +167,17 @@ abstract class X509KeyManagerCertChecking extends X509ExtendedKeyManager { return null; } - if (socket != null && socket.isConnected() && - socket instanceof SSLSocket sslSocket) { - + if (socket instanceof SSLSocket sslSocket && sslSocket.isConnected()) { SSLSession session = sslSocket.getHandshakeSession(); - if (session != null) { - if (ProtocolVersion.useTLS12PlusSpec(session.getProtocol())) { - String[] peerSupportedSignAlgs = null; - - if (session instanceof ExtendedSSLSession extSession) { - // Peer supported certificate signature algorithms - // sent with "signature_algorithms_cert" TLS extension. - peerSupportedSignAlgs = - extSession.getPeerSupportedSignatureAlgorithms(); - } - - return SSLAlgorithmConstraints.forSocket( - sslSocket, peerSupportedSignAlgs, true); - } + if (session instanceof ExtendedSSLSession extSession + && ProtocolVersion.useTLS12PlusSpec( + extSession.getProtocol())) { + // Use peer supported certificate signature algorithms + // sent with "signature_algorithms_cert" TLS extension. + return SSLAlgorithmConstraints.forSocket(sslSocket, + extSession.getPeerSupportedSignatureAlgorithms(), + true); } return SSLAlgorithmConstraints.forSocket(sslSocket, true); @@ -203,20 +195,15 @@ abstract class X509KeyManagerCertChecking extends X509ExtendedKeyManager { if (engine != null) { SSLSession session = engine.getHandshakeSession(); - if (session != null) { - if (ProtocolVersion.useTLS12PlusSpec(session.getProtocol())) { - String[] peerSupportedSignAlgs = null; - if (session instanceof ExtendedSSLSession extSession) { - // Peer supported certificate signature algorithms - // sent with "signature_algorithms_cert" TLS extension. - peerSupportedSignAlgs = - extSession.getPeerSupportedSignatureAlgorithms(); - } - - return SSLAlgorithmConstraints.forEngine( - engine, peerSupportedSignAlgs, true); - } + if (session instanceof ExtendedSSLSession extSession + && ProtocolVersion.useTLS12PlusSpec( + extSession.getProtocol())) { + // Use peer supported certificate signature algorithms + // sent with "signature_algorithms_cert" TLS extension. + return SSLAlgorithmConstraints.forEngine(engine, + extSession.getPeerSupportedSignatureAlgorithms(), + true); } } diff --git a/test/jdk/sun/security/ssl/X509KeyManager/AlgorithmConstraintsCheck.java b/test/jdk/sun/security/ssl/X509KeyManager/AlgorithmConstraintsCheck.java index 997fde5a07a..4caa7b6b944 100644 --- a/test/jdk/sun/security/ssl/X509KeyManager/AlgorithmConstraintsCheck.java +++ b/test/jdk/sun/security/ssl/X509KeyManager/AlgorithmConstraintsCheck.java @@ -57,31 +57,31 @@ import sun.security.x509.X500Name; * @modules java.base/sun.security.x509 * java.base/sun.security.util * @library /test/lib - * @run main/othervm AlgorithmConstraintsCheck false SunX509 SHA256withRSA - * @run main/othervm AlgorithmConstraintsCheck true SunX509 SHA256withRSA - * @run main/othervm AlgorithmConstraintsCheck false PKIX SHA256withRSA - * @run main/othervm AlgorithmConstraintsCheck true PKIX SHA256withRSA + * @run main/othervm AlgorithmConstraintsCheck false SunX509 + * @run main/othervm AlgorithmConstraintsCheck true SunX509 + * @run main/othervm AlgorithmConstraintsCheck false PKIX + * @run main/othervm AlgorithmConstraintsCheck true PKIX */ public class AlgorithmConstraintsCheck { - private static final String CERT_ALIAS = "testalias"; - private static final String KEY_TYPE = "RSA"; + protected static final String CERT_ALIAS = "testalias"; + protected static final String KEY_TYPE = "EC"; + protected static final String CERT_SIG_ALG = "SHA256withECDSA"; public static void main(String[] args) throws Exception { - if (args.length != 3) { + if (args.length != 2) { throw new RuntimeException("Wrong number of arguments"); } String enabled = args[0]; String kmAlg = args[1]; - String certSignatureAlg = args[2]; System.setProperty("jdk.tls.SunX509KeyManager.certChecking", enabled); - SecurityUtils.addToDisabledTlsAlgs(certSignatureAlg); + SecurityUtils.addToDisabledTlsAlgs(CERT_SIG_ALG); X509ExtendedKeyManager km = (X509ExtendedKeyManager) getKeyManager( - kmAlg, certSignatureAlg); + kmAlg, KEY_TYPE, CERT_SIG_ALG); String serverAlias = km.chooseServerAlias(KEY_TYPE, null, null); String engineServerAlias = km.chooseEngineServerAlias( KEY_TYPE, null, null); @@ -108,13 +108,13 @@ public class AlgorithmConstraintsCheck { } // PKIX KeyManager adds a cache prefix to an alias. - private static String normalizeAlias(String alias) { + protected static String normalizeAlias(String alias) { return alias.substring(alias.lastIndexOf(".") + 1); } - private static X509KeyManager getKeyManager(String kmAlg, - String certSignatureAlg) throws Exception { - KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_TYPE); + protected static X509KeyManager getKeyManager(String kmAlg, + String keyAlg, String certSignatureAlg) throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlg); KeyPair caKeys = kpg.generateKeyPair(); KeyPair endpointKeys = kpg.generateKeyPair(); diff --git a/test/jdk/sun/security/ssl/X509KeyManager/NonExtendedSSLSessionAlgorithmConstraints.java b/test/jdk/sun/security/ssl/X509KeyManager/NonExtendedSSLSessionAlgorithmConstraints.java new file mode 100644 index 00000000000..30ec655f7b2 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509KeyManager/NonExtendedSSLSessionAlgorithmConstraints.java @@ -0,0 +1,405 @@ +/* + * 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 8365953 + * @summary Key manager returns no certificates when handshakeSession is not + * an ExtendedSSLSession + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + * @library /test/lib + * @run main/othervm NonExtendedSSLSessionAlgorithmConstraints + */ + +import static jdk.test.lib.Asserts.assertEquals; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.Principal; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.X509ExtendedKeyManager; + +/* + * Make sure Key Managers return the certificates when SSLSocket or SSLEngine + * use an SSLSession which is not extending ExtendedSSLSession. + */ +public class NonExtendedSSLSessionAlgorithmConstraints extends + AlgorithmConstraintsCheck { + + public static void main(String[] args) throws Exception { + new NonExtendedSSLSessionAlgorithmConstraints().runTest(); + } + + private void runTest() throws Exception { + for (String kmAlg : new String[]{"SunX509", "PKIX"}) { + + X509ExtendedKeyManager km = + (X509ExtendedKeyManager) getKeyManager( + kmAlg, KEY_TYPE, CERT_SIG_ALG); + var testSocket = new TestHandshakeSessionSSLSocket(); + var testEngine = new TestHandshakeSessionSSLEngine(); + + // Test SSLSocket + assertEquals(CERT_ALIAS, normalizeAlias(km.chooseServerAlias( + KEY_TYPE, null, testSocket))); + assertEquals(CERT_ALIAS, normalizeAlias(km.chooseClientAlias( + new String[]{KEY_TYPE}, null, testSocket))); + + // Test SSLEngine + assertEquals(CERT_ALIAS, normalizeAlias(km.chooseEngineServerAlias( + KEY_TYPE, null, testEngine))); + assertEquals(CERT_ALIAS, normalizeAlias(km.chooseEngineClientAlias( + new String[]{KEY_TYPE}, null, testEngine))); + } + } + + private static class TestHandshakeSessionSSLSocket extends SSLSocket { + + TestHandshakeSessionSSLSocket() { + } + + @Override + public SSLSession getHandshakeSession() { + return new TestSSLSession(); + } + + @Override + public boolean isConnected() { + return true; + } + + @Override + public SSLSession getSession() { + return null; + } + + @Override + public String[] getSupportedCipherSuites() { + return null; + } + + @Override + public String[] getSupportedProtocols() { + return null; + } + + @Override + public String[] getEnabledCipherSuites() { + return null; + } + + @Override + public void setEnabledCipherSuites(String[] suites) { + } + + @Override + public String[] getEnabledProtocols() { + return null; + } + + @Override + public void setEnabledProtocols(String[] protocols) { + } + + @Override + public void addHandshakeCompletedListener + (HandshakeCompletedListener listener) { + } + + @Override + public void removeHandshakeCompletedListener + (HandshakeCompletedListener listener) { + } + + @Override + public void startHandshake() throws IOException { + } + + @Override + public void setUseClientMode(boolean mode) { + } + + @Override + public boolean getUseClientMode() { + return false; + } + + @Override + public void setNeedClientAuth(boolean need) { + } + + @Override + public boolean getNeedClientAuth() { + return false; + } + + @Override + public void setWantClientAuth(boolean want) { + } + + @Override + public boolean getWantClientAuth() { + return false; + } + + @Override + public void setEnableSessionCreation(boolean flag) { + } + + @Override + public boolean getEnableSessionCreation() { + return true; + } + } + + private static class TestHandshakeSessionSSLEngine extends SSLEngine { + + @Override + public SSLSession getHandshakeSession() { + return new TestSSLSession(); + } + + @Override + public String[] getEnabledProtocols() { + return null; + } + + @Override + public SSLEngineResult wrap(ByteBuffer[] src, int off, int len, + ByteBuffer dst) throws SSLException { + return null; + } + + @Override + public SSLEngineResult unwrap(ByteBuffer src, + ByteBuffer[] dst, int off, int len) + throws SSLException { + return null; + } + + @Override + public Runnable getDelegatedTask() { + return null; + } + + @Override + public void closeInbound() { + } + + @Override + public boolean isInboundDone() { + return false; + } + + @Override + public void closeOutbound() { + } + + @Override + public boolean isOutboundDone() { + return false; + } + + @Override + public String[] getEnabledCipherSuites() { + return null; + } + + @Override + public String[] getSupportedCipherSuites() { + return null; + } + + @Override + public void setEnabledCipherSuites(String[] suites) { + } + + @Override + public String[] getSupportedProtocols() { + return null; + } + + @Override + public void setEnabledProtocols(String[] protocols) { + } + + @Override + public SSLSession getSession() { + return null; + } + + @Override + public void beginHandshake() { + } + + @Override + public SSLEngineResult.HandshakeStatus getHandshakeStatus() { + return null; + } + + @Override + public void setUseClientMode(boolean mode) { + } + + @Override + public boolean getUseClientMode() { + return false; + } + + public void setNeedClientAuth(boolean need) { + } + + @Override + public boolean getNeedClientAuth() { + return false; + } + + @Override + public void setWantClientAuth(boolean need) { + } + + @Override + public boolean getWantClientAuth() { + return false; + } + + @Override + public void setEnableSessionCreation(boolean flag) { + } + + @Override + public boolean getEnableSessionCreation() { + return false; + } + } + + public static class TestSSLSession implements SSLSession { + + TestSSLSession() { + } + + @Override + public String getProtocol() { + return "TLSv1.3"; + } + + @Override + public byte[] getId() { + return null; + } + + @Override + public SSLSessionContext getSessionContext() { + return null; + } + + @Override + public long getCreationTime() { + return 0; + } + + @Override + public long getLastAccessedTime() { + return 0; + } + + @Override + public void invalidate() { + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public void putValue(String name, Object value) { + } + + @Override + public Object getValue(String name) { + return null; + } + + @Override + public void removeValue(String name) { + } + + @Override + public String[] getValueNames() { + return null; + } + + @Override + public java.security.cert.Certificate[] getPeerCertificates() { + return new java.security.cert.Certificate[0]; + } + + @Override + public java.security.cert.Certificate[] getLocalCertificates() { + return new java.security.cert.Certificate[0]; + } + + @Override + public Principal getPeerPrincipal() { + return null; + } + + @Override + public Principal getLocalPrincipal() { + return null; + } + + @Override + public String getCipherSuite() { + return null; + } + + @Override + public String getPeerHost() { + return null; + } + + @Override + public int getPeerPort() { + return 0; + } + + @Override + public int getPacketBufferSize() { + return 0; + } + + @Override + public int getApplicationBufferSize() { + return 0; + } + } +} From 781f2b2f8188c02a6af220ebcc5bc8158fe8423e Mon Sep 17 00:00:00 2001 From: Pasam Soujanya Date: Thu, 11 Sep 2025 13:58:51 +0000 Subject: [PATCH 0014/1116] 8366278: Form control element + + + """; + Document doc = kit.createDefaultDocument(); + editorPane.setDocument(doc); + editorPane.setText(htmlString); + + frame.add(scrollPane, BorderLayout.CENTER); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(new Dimension(400, 200)); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static boolean containsAlt(Container container) { + for (Component c : container.getComponents()) { + if (c instanceof JButton button) { + return "Logo".equals(button.getText()); + } else if (c instanceof Container cont) { + return containsAlt(cont); + } + } + return false; + } +} From 64155dfac068cf01bcab6adb401b360499f33a5f Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 15 Sep 2025 21:10:26 +0000 Subject: [PATCH 0057/1116] 8367237: Thread-Safety Usage Warning for java.text.Collator Classes Reviewed-by: iris, naoto --- src/java.base/share/classes/java/text/Collator.java | 9 +++++++-- .../share/classes/java/text/RuleBasedCollator.java | 11 ++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/text/Collator.java b/src/java.base/share/classes/java/text/Collator.java index 276a66cdc07..5e576cd800f 100644 --- a/src/java.base/share/classes/java/text/Collator.java +++ b/src/java.base/share/classes/java/text/Collator.java @@ -111,8 +111,13 @@ import sun.util.locale.provider.LocaleServiceProviderPool; *
* @apiNote {@code CollationKey}s from different * {@code Collator}s can not be compared. See the class description - * for {@link CollationKey} - * for an example using {@code CollationKey}s. + * for {@link CollationKey} for an example using {@code CollationKey}s. + * + * @implNote Significant thread contention may occur during concurrent usage + * of the JDK Reference Implementation's {@link RuleBasedCollator}, which is the + * subtype returned by the default provider of the {@link #getInstance()} factory + * methods. As such, users should consider retrieving a separate instance for + * each thread when used in multithreaded environments. * * @see RuleBasedCollator * @see CollationKey diff --git a/src/java.base/share/classes/java/text/RuleBasedCollator.java b/src/java.base/share/classes/java/text/RuleBasedCollator.java index dc45dafb846..af1b6b62bdf 100644 --- a/src/java.base/share/classes/java/text/RuleBasedCollator.java +++ b/src/java.base/share/classes/java/text/RuleBasedCollator.java @@ -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 @@ -38,10 +38,6 @@ package java.text; -import java.text.Normalizer; -import java.util.Vector; -import java.util.Locale; - /** * The {@code RuleBasedCollator} class is a concrete subclass of * {@code Collator} that provides a simple, data-driven, table @@ -239,6 +235,11 @@ import java.util.Locale; * * * + * @implNote For this implementation, concurrent usage of this class may + * lead to significant thread contention since {@code synchronized} is employed + * to ensure thread-safety. As such, users of this class should consider creating + * a separate instance for each thread when used in multithreaded environments. + * * @see Collator * @see CollationElementIterator * @author Helena Shih, Laura Werner, Richard Gillam From 242558484985cb954b0e658776fd59cbca1be1db Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 16 Sep 2025 01:04:48 +0000 Subject: [PATCH 0058/1116] 8367142: Avoid InstanceKlass::cast when converting java mirror to InstanceKlass Reviewed-by: dholmes, coleenp --- src/hotspot/share/cds/aotMetaspace.cpp | 4 +- src/hotspot/share/cds/unregisteredClasses.cpp | 2 +- src/hotspot/share/classfile/javaClasses.cpp | 27 +++--- src/hotspot/share/classfile/javaClasses.hpp | 12 +-- .../share/classfile/javaClasses.inline.hpp | 6 ++ .../share/classfile/systemDictionary.cpp | 4 +- .../jfr/leakprofiler/chains/edgeUtils.cpp | 2 +- src/hotspot/share/jvmci/jvmciRuntime.cpp | 2 +- src/hotspot/share/prims/jni.cpp | 2 +- src/hotspot/share/prims/jvm.cpp | 82 +++++++------------ src/hotspot/share/prims/methodHandles.cpp | 2 +- src/hotspot/share/prims/unsafe.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 26 +++--- src/hotspot/share/runtime/reflection.cpp | 4 +- src/hotspot/share/runtime/sharedRuntime.cpp | 4 +- 15 files changed, 80 insertions(+), 101 deletions(-) diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index 01bc4708eb5..b3f859fc4a8 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -785,7 +785,7 @@ void AOTMetaspace::link_all_loaded_classes(JavaThread* current) { const GrowableArray* mirrors = collect_classes.mirrors(); for (int i = 0; i < mirrors->length(); i++) { OopHandle mirror = mirrors->at(i); - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(mirror.resolve())); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror.resolve()); if (may_be_eagerly_linked(ik)) { has_linked |= try_link_class(current, ik); } @@ -812,7 +812,7 @@ void AOTMetaspace::link_shared_classes(TRAPS) { const GrowableArray* mirrors = collect_classes.mirrors(); for (int i = 0; i < mirrors->length(); i++) { OopHandle mirror = mirrors->at(i); - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(mirror.resolve())); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror.resolve()); AOTConstantPoolResolver::preresolve_string_cp_entries(ik, CHECK); } } diff --git a/src/hotspot/share/cds/unregisteredClasses.cpp b/src/hotspot/share/cds/unregisteredClasses.cpp index 31cfbd15d67..51b35899599 100644 --- a/src/hotspot/share/cds/unregisteredClasses.cpp +++ b/src/hotspot/share/cds/unregisteredClasses.cpp @@ -94,7 +94,7 @@ InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path, T CHECK_NULL); assert(result.get_type() == T_OBJECT, "just checking"); - return InstanceKlass::cast(java_lang_Class::as_Klass(result.get_oop())); + return java_lang_Class::as_InstanceKlass(result.get_oop()); } bool UnregisteredClasses::check_for_exclusion(const InstanceKlass* k) { diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 86a3b22fbbb..da093936ce5 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -990,7 +990,7 @@ void java_lang_Class::fixup_mirror(Klass* k, TRAPS) { create_mirror(k, Handle(), Handle(), Handle(), Handle(), CHECK); } -void java_lang_Class::initialize_mirror_fields(Klass* k, +void java_lang_Class::initialize_mirror_fields(InstanceKlass* ik, Handle mirror, Handle protection_domain, Handle classData, @@ -1005,7 +1005,7 @@ void java_lang_Class::initialize_mirror_fields(Klass* k, set_protection_domain(mirror(), protection_domain()); // Initialize static fields - InstanceKlass::cast(k)->do_local_static_fields(&initialize_static_field, mirror, CHECK); + ik->do_local_static_fields(&initialize_static_field, mirror, CHECK); // Set classData set_class_data(mirror(), classData()); @@ -1111,8 +1111,7 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // and java_mirror in this klass. } else { assert(k->is_instance_klass(), "Must be"); - - initialize_mirror_fields(k, mirror, protection_domain, classData, THREAD); + initialize_mirror_fields(InstanceKlass::cast(k), mirror, protection_domain, classData, THREAD); if (HAS_PENDING_EXCEPTION) { // If any of the fields throws an exception like OOM remove the klass field // from the mirror so GC doesn't follow it after the klass has been deallocated. @@ -2590,7 +2589,7 @@ static void print_stack_element_to_stream(outputStream* st, Handle mirror, int m ResourceMark rm; stringStream ss; - InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); + InstanceKlass* holder = java_lang_Class::as_InstanceKlass(mirror()); const char* klass_name = holder->external_name(); char* method_name = name->as_C_string(); ss.print("\tat %s.%s(", klass_name, method_name); @@ -2969,7 +2968,7 @@ void java_lang_Throwable::get_stack_trace_elements(int depth, Handle backtrace, THROW(vmSymbols::java_lang_NullPointerException()); } - InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(bte._mirror())); + InstanceKlass* holder = java_lang_Class::as_InstanceKlass(bte._mirror()); methodHandle method (THREAD, holder->method_with_orig_idnum(bte._method_id, bte._version)); java_lang_StackTraceElement::fill_in(stack_trace_element, holder, @@ -3055,7 +3054,7 @@ bool java_lang_Throwable::get_top_method_and_bci(oop throwable, Method** method, // Get first backtrace element. BacktraceElement bte = iter.next(current); - InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(bte._mirror())); + InstanceKlass* holder = java_lang_Class::as_InstanceKlass(bte._mirror()); assert(holder != nullptr, "first element should be non-null"); Method* m = holder->method_with_orig_idnum(bte._method_id, bte._version); @@ -3441,11 +3440,11 @@ void java_lang_reflect_Method::serialize_offsets(SerializeClosure* f) { Handle java_lang_reflect_Method::create(TRAPS) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); - Klass* klass = vmClasses::reflect_Method_klass(); + InstanceKlass* klass = vmClasses::reflect_Method_klass(); // This class is eagerly initialized during VM initialization, since we keep a reference // to one of the methods - assert(InstanceKlass::cast(klass)->is_initialized(), "must be initialized"); - return InstanceKlass::cast(klass)->allocate_instance_handle(THREAD); + assert(klass->is_initialized(), "must be initialized"); + return klass->allocate_instance_handle(THREAD); } oop java_lang_reflect_Method::clazz(oop reflect) { @@ -3914,17 +3913,15 @@ void reflect_ConstantPool::set_cp(oop reflect, ConstantPool* value) { } ConstantPool* reflect_ConstantPool::get_cp(oop reflect) { - oop mirror = reflect->obj_field(_oop_offset); - Klass* k = java_lang_Class::as_Klass(mirror); - assert(k->is_instance_klass(), "Must be"); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror); // Get the constant pool back from the klass. Since class redefinition // merges the new constant pool into the old, this is essentially the // same constant pool as the original. If constant pool merging is // no longer done in the future, this will have to change to save // the original. - return InstanceKlass::cast(k)->constants(); + return ik->constants(); } @@ -5531,7 +5528,7 @@ void JavaClasses::check_offsets() { #endif // PRODUCT int InjectedField::compute_offset() { - InstanceKlass* ik = InstanceKlass::cast(klass()); + InstanceKlass* ik = klass(); for (AllFieldStream fs(ik); !fs.done(); fs.next()) { if (!may_be_java && !fs.field_flags().is_injected()) { // Only look at injected fields diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 70fa519f0f0..6f82ca10fd6 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -269,7 +269,7 @@ class java_lang_Class : AllStatic { static void set_protection_domain(oop java_class, oop protection_domain); static void set_class_loader(oop java_class, oop class_loader); static void set_component_mirror(oop java_class, oop comp_mirror); - static void initialize_mirror_fields(Klass* k, Handle mirror, Handle protection_domain, + static void initialize_mirror_fields(InstanceKlass* ik, Handle mirror, Handle protection_domain, Handle classData, TRAPS); static void set_mirror_module_field(JavaThread* current, Klass* K, Handle mirror, Handle module); public: @@ -293,8 +293,10 @@ class java_lang_Class : AllStatic { static void fixup_module_field(Klass* k, Handle module); - // Conversion + // Conversion -- java_class must not be null. The return value is null only if java_class is a primitive type. static Klass* as_Klass(oop java_class); + static InstanceKlass* as_InstanceKlass(oop java_class); + static void set_klass(oop java_class, Klass* klass); static BasicType as_BasicType(oop java_class, Klass** reference_klass = nullptr); static Symbol* as_signature(oop java_class, bool intern_if_not_found); @@ -1895,11 +1897,11 @@ class InjectedField { const vmClassID klass_id; const vmSymbolID name_index; const vmSymbolID signature_index; - const bool may_be_java; + const bool may_be_java; - Klass* klass() const { return vmClasses::klass_at(klass_id); } - Symbol* name() const { return lookup_symbol(name_index); } + InstanceKlass* klass() const { return vmClasses::klass_at(klass_id); } + Symbol* name() const { return lookup_symbol(name_index); } Symbol* signature() const { return lookup_symbol(signature_index); } int compute_offset(); diff --git a/src/hotspot/share/classfile/javaClasses.inline.hpp b/src/hotspot/share/classfile/javaClasses.inline.hpp index 3cbbd2c12f2..21ad62f8408 100644 --- a/src/hotspot/share/classfile/javaClasses.inline.hpp +++ b/src/hotspot/share/classfile/javaClasses.inline.hpp @@ -291,6 +291,12 @@ inline Klass* java_lang_Class::as_Klass(oop java_class) { return k; } +inline InstanceKlass* java_lang_Class::as_InstanceKlass(oop java_class) { + Klass* k = as_Klass(java_class); + assert(k == nullptr || k->is_instance_klass(), "type check"); + return static_cast(k); +} + inline bool java_lang_Class::is_primitive(oop java_class) { // should assert: // assert(java_lang_Class::is_instance(java_class), "must be a Class object"); diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 22d4fd1892e..95f86a8950b 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1277,10 +1277,10 @@ InstanceKlass* SystemDictionary::load_instance_class_impl(Symbol* class_name, Ha assert(result.get_type() == T_OBJECT, "just checking"); oop obj = result.get_oop(); - // Primitive classes return null since forName() can not be + // Primitive classes return null since forName() cannot be // used to obtain any of the Class objects representing primitives or void if ((obj != nullptr) && !(java_lang_Class::is_primitive(obj))) { - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(obj)); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(obj); // For user defined Java class loaders, check that the name returned is // the same as that requested. This check is done for the bootstrap // loader when parsing the class file. diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp index d431d98e383..da098634ba6 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp @@ -65,7 +65,7 @@ const Symbol* EdgeUtils::field_name(const Edge& edge, jshort* modifiers) { if (is_static_field(ref_owner, ik, offset)) { assert(ik->is_mirror_instance_klass(), "invariant"); assert(java_lang_Class::as_Klass(ref_owner)->is_instance_klass(), "invariant"); - ik = InstanceKlass::cast(java_lang_Class::as_Klass(ref_owner)); + ik = java_lang_Class::as_InstanceKlass(ref_owner); } while (ik != nullptr) { JavaFieldStream jfs(ik); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index c7c3a00a127..137782f93ef 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -187,7 +187,7 @@ JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array_or_null(JavaThread* current, oop JRT_END JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance_or_null(JavaThread* current, oopDesc* type_mirror)) - InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(type_mirror)); + InstanceKlass* klass = java_lang_Class::as_InstanceKlass(type_mirror); if (klass == nullptr) { ResourceMark rm(current); diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 0e469dd7f84..34d2d614d22 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -526,7 +526,7 @@ JNI_ENTRY(jint, jni_ThrowNew(JNIEnv *env, jclass clazz, const char *message)) jint ret = JNI_OK; DT_RETURN_MARK(ThrowNew, jint, (const jint&)ret); - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(clazz)); Symbol* name = k->name(); Handle class_loader (THREAD, k->class_loader()); THROW_MSG_LOADER_(name, (char *)message, class_loader, JNI_OK); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index daacfd4ab7a..2cbe764994d 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -840,14 +840,9 @@ JVM_ENTRY(jclass, JVM_FindClassFromClass(JNIEnv *env, const char *name, if (log_is_enabled(Debug, class, resolve) && result != nullptr) { // this function is generally only used for class loading during verification. ResourceMark rm; - oop from_mirror = JNIHandles::resolve_non_null(from); - Klass* from_class = java_lang_Class::as_Klass(from_mirror); - const char * from_name = from_class->external_name(); - - oop mirror = JNIHandles::resolve_non_null(result); - Klass* to_class = java_lang_Class::as_Klass(mirror); - const char * to = to_class->external_name(); - log_debug(class, resolve)("%s %s (verification)", from_name, to); + const char* from_name = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(from))->external_name(); + const char* to_name = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))->external_name(); + log_debug(class, resolve)("%s %s (verification)", from_name, to_name); } #if INCLUDE_CDS @@ -918,12 +913,12 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name, jboolean init, int flags, jobject classData, TRAPS) { ResourceMark rm(THREAD); - Klass* lookup_k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(lookup)); - // Lookup class must be a non-null instance + InstanceKlass* lookup_k = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(lookup)); + // Lookup class must not be a primitive class (whose mirror has a null Klass*) if (lookup_k == nullptr) { + // The error message is wrong. We come here only if lookup is a primitive class THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null"); } - assert(lookup_k->is_instance_klass(), "Lookup class must be an instance klass"); Handle class_loader (THREAD, lookup_k->class_loader()); @@ -934,7 +929,7 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name, InstanceKlass* host_class = nullptr; if (is_nestmate) { - host_class = InstanceKlass::cast(lookup_k)->nest_host(CHECK_NULL); + host_class = lookup_k->nest_host(CHECK_NULL); } log_info(class, nestmates)("LookupDefineClass: %s - %s%s, %s, %s, %s", @@ -1265,7 +1260,7 @@ JVM_ENTRY(jobjectArray, JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass)) return (jobjectArray)JNIHandles::make_local(THREAD, result); } - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(ofMirror)); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(ofMirror); InnerClassesIterator iter(k); if (iter.length() == 0) { @@ -1404,11 +1399,10 @@ static bool jvm_get_field_common(jobject field, fieldDescriptor& fd) { oop reflected = JNIHandles::resolve_non_null(field); oop mirror = java_lang_reflect_Field::clazz(reflected); - Klass* k = java_lang_Class::as_Klass(mirror); int slot = java_lang_reflect_Field::slot(reflected); int modifiers = java_lang_reflect_Field::modifiers(reflected); - InstanceKlass* ik = InstanceKlass::cast(k); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror); int offset = ik->field_offset(slot); if (modifiers & JVM_ACC_STATIC) { @@ -1444,9 +1438,9 @@ static Method* jvm_get_method_common(jobject method) { mirror = java_lang_reflect_Method::clazz(reflected); slot = java_lang_reflect_Method::slot(reflected); } - Klass* k = java_lang_Class::as_Klass(mirror); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror); - Method* m = InstanceKlass::cast(k)->method_with_idnum(slot); + Method* m = ik->method_with_idnum(slot); assert(m != nullptr, "cannot find method"); return m; // caller has to deal with null in product mode } @@ -1570,7 +1564,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, return (jobjectArray) JNIHandles::make_local(THREAD, res); } - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(ofMirror)); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(ofMirror); constantPoolHandle cp(THREAD, k->constants()); // Ensure class is linked @@ -1627,9 +1621,7 @@ JVM_END // even if the class is not a record. JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass)) { - Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass)); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ik = InstanceKlass::cast(c); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(ofClass)); Array* components = ik->record_components(); if (components != nullptr) { @@ -1671,7 +1663,7 @@ static jobjectArray get_class_declared_methods_helper( return (jobjectArray) JNIHandles::make_local(THREAD, res); } - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(ofMirror)); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(ofMirror); // Ensure class is linked k->link_class(CHECK_NULL); @@ -1750,23 +1742,17 @@ JVM_END JVM_ENTRY(jboolean, JVM_AreNestMates(JNIEnv *env, jclass current, jclass member)) { - Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current)); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ck = InstanceKlass::cast(c); - Klass* m = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(member)); - assert(m->is_instance_klass(), "must be"); - InstanceKlass* mk = InstanceKlass::cast(m); - return ck->has_nestmate_access_to(mk, THREAD); + InstanceKlass* c = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(current)); + InstanceKlass* m = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(member)); + return c->has_nestmate_access_to(m, THREAD); } JVM_END JVM_ENTRY(jclass, JVM_GetNestHost(JNIEnv* env, jclass current)) { // current is not a primitive or array class - Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current)); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ck = InstanceKlass::cast(c); - InstanceKlass* host = ck->nest_host(THREAD); + InstanceKlass* c = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(current)); + InstanceKlass* host = c->nest_host(THREAD); return (jclass) (host == nullptr ? nullptr : JNIHandles::make_local(THREAD, host->java_mirror())); } @@ -1776,13 +1762,11 @@ JVM_ENTRY(jobjectArray, JVM_GetNestMembers(JNIEnv* env, jclass current)) { // current is not a primitive or array class ResourceMark rm(THREAD); - Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current)); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ck = InstanceKlass::cast(c); - InstanceKlass* host = ck->nest_host(THREAD); + InstanceKlass* c = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(current)); + InstanceKlass* host = c->nest_host(THREAD); log_trace(class, nestmates)("Calling GetNestMembers for type %s with nest-host %s", - ck->external_name(), host->external_name()); + c->external_name(), host->external_name()); { JvmtiVMObjectAllocEventCollector oam; Array* members = host->nest_members(); @@ -1845,7 +1829,7 @@ JVM_ENTRY(jobjectArray, JVM_GetNestMembers(JNIEnv* env, jclass current)) } } else { - assert(host == ck || ck->is_hidden(), "must be singleton nest or dynamic nestmate"); + assert(host == c || c->is_hidden(), "must be singleton nest or dynamic nestmate"); } return (jobjectArray)JNIHandles::make_local(THREAD, result()); } @@ -1856,9 +1840,8 @@ JVM_ENTRY(jobjectArray, JVM_GetPermittedSubclasses(JNIEnv* env, jclass current)) { oop mirror = JNIHandles::resolve_non_null(current); assert(!java_lang_Class::is_primitive(mirror), "should not be"); - Klass* c = java_lang_Class::as_Klass(mirror); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ik = InstanceKlass::cast(c); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror); + ResourceMark rm(THREAD); log_trace(class, sealed)("Calling GetPermittedSubclasses for %s type %s", ik->is_sealed() ? "sealed" : "non-sealed", ik->external_name()); @@ -3379,16 +3362,14 @@ JVM_ENTRY(void, JVM_RegisterLambdaProxyClassForArchiving(JNIEnv* env, return; } - Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller)); - InstanceKlass* caller_ik = InstanceKlass::cast(caller_k); + InstanceKlass* caller_ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(caller)); if (caller_ik->is_hidden()) { // Hidden classes not of type lambda proxy classes are currently not being archived. // If the caller_ik is of one of the above types, the corresponding lambda proxy class won't be // registered for archiving. return; } - Klass* lambda_k = java_lang_Class::as_Klass(JNIHandles::resolve(lambdaProxyClass)); - InstanceKlass* lambda_ik = InstanceKlass::cast(lambda_k); + InstanceKlass* lambda_ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(lambdaProxyClass)); assert(lambda_ik->is_hidden(), "must be a hidden class"); assert(!lambda_ik->is_non_strong_hidden(), "expected a strong hidden class"); @@ -3428,8 +3409,7 @@ JVM_ENTRY(jclass, JVM_LookupLambdaProxyClassFromArchive(JNIEnv* env, THROW_(vmSymbols::java_lang_NullPointerException(), nullptr); } - Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller)); - InstanceKlass* caller_ik = InstanceKlass::cast(caller_k); + InstanceKlass* caller_ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(caller)); if (!caller_ik->in_aot_cache()) { // there won't be a shared lambda class if the caller_ik is not in the shared archive. return nullptr; @@ -3825,11 +3805,7 @@ JVM_ENTRY(jint, JVM_GetClassFileVersion(JNIEnv* env, jclass current)) // return latest major version and minor version of 0. return JVM_CLASSFILE_MAJOR_VERSION; } - assert(!java_lang_Class::as_Klass(mirror)->is_array_klass(), "unexpected array class"); - - Klass* c = java_lang_Class::as_Klass(mirror); - assert(c->is_instance_klass(), "must be"); - InstanceKlass* ik = InstanceKlass::cast(c); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(mirror); return (ik->minor_version() << 16) | ik->major_version(); JVM_END diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index c46b46b1af1..b13bd392eaa 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -902,7 +902,7 @@ void MethodHandles::expand_MemberName(Handle mname, int suppress, TRAPS) { if (clazz == nullptr) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "nothing to expand (as field)"); } - InstanceKlass* defc = InstanceKlass::cast(java_lang_Class::as_Klass(clazz)); + InstanceKlass* defc = java_lang_Class::as_InstanceKlass(clazz); DEBUG_ONLY(clazz = nullptr); // safety intptr_t vmindex = java_lang_invoke_MemberName::vmindex(mname()); bool is_static = ((flags & JVM_ACC_STATIC) != 0); diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 4b2ffd57860..c950690e8ab 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -489,7 +489,7 @@ static jlong find_known_instance_field_offset(jclass clazz, jstring name, TRAPS) ResourceMark rm(THREAD); char *utf_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(name)); - InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); + InstanceKlass* k = java_lang_Class::as_InstanceKlass(JNIHandles::resolve_non_null(clazz)); jint offset = -1; // Not found for (JavaFieldStream fs(k); !fs.done(); fs.next()) { diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index afaa089e0b2..ce559d47b24 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1156,7 +1156,7 @@ WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobjec WB_END WB_ENTRY(jboolean, WB_EnqueueInitializerForCompilation(JNIEnv* env, jobject o, jclass klass, jint comp_level)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); Method* clinit = ik->class_initializer(); if (clinit == nullptr || clinit->method_holder()->is_not_initialized()) { return false; @@ -1936,18 +1936,18 @@ WB_ENTRY(void, WB_ForceClassLoaderStatsSafepoint(JNIEnv* env, jobject wb)) WB_END WB_ENTRY(jlong, WB_GetConstantPool(JNIEnv* env, jobject wb, jclass klass)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); return (jlong) ik->constants(); WB_END WB_ENTRY(jobjectArray, WB_GetResolvedReferences(JNIEnv* env, jobject wb, jclass klass)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); objArrayOop resolved_refs= ik->constants()->resolved_references(); return (jobjectArray)JNIHandles::make_local(THREAD, resolved_refs); WB_END WB_ENTRY(jint, WB_getFieldEntriesLength(JNIEnv* env, jobject wb, jclass klass)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -1956,7 +1956,7 @@ WB_ENTRY(jint, WB_getFieldEntriesLength(JNIEnv* env, jobject wb, jclass klass)) WB_END WB_ENTRY(jint, WB_getFieldCPIndex(JNIEnv* env, jobject wb, jclass klass, jint index)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -1965,7 +1965,7 @@ WB_ENTRY(jint, WB_getFieldCPIndex(JNIEnv* env, jobject wb, jclass klass, jint in WB_END WB_ENTRY(jint, WB_getMethodEntriesLength(JNIEnv* env, jobject wb, jclass klass)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -1974,7 +1974,7 @@ WB_ENTRY(jint, WB_getMethodEntriesLength(JNIEnv* env, jobject wb, jclass klass)) WB_END WB_ENTRY(jint, WB_getMethodCPIndex(JNIEnv* env, jobject wb, jclass klass, jint index)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -1983,7 +1983,7 @@ WB_ENTRY(jint, WB_getMethodCPIndex(JNIEnv* env, jobject wb, jclass klass, jint i WB_END WB_ENTRY(jint, WB_getIndyInfoLength(JNIEnv* env, jobject wb, jclass klass)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -1992,7 +1992,7 @@ WB_ENTRY(jint, WB_getIndyInfoLength(JNIEnv* env, jobject wb, jclass klass)) WB_END WB_ENTRY(jint, WB_getIndyCPIndex(JNIEnv* env, jobject wb, jclass klass, jint index)) - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(klass)); ConstantPool* cp = ik->constants(); if (cp->cache() == nullptr) { return -1; @@ -2386,10 +2386,8 @@ int WhiteBox::offset_for_field(const char* field_name, oop object, Symbol* signature_symbol) { assert(field_name != nullptr && strlen(field_name) > 0, "Field name not valid"); - //Get the class of our object - Klass* arg_klass = object->klass(); - //Turn it into an instance-klass - InstanceKlass* ik = InstanceKlass::cast(arg_klass); + //Only non-array oops have fields. Don't call this function on arrays! + InstanceKlass* ik = InstanceKlass::cast(object->klass()); //Create symbols to look for in the class TempNewSymbol name_symbol = SymbolTable::new_symbol(field_name); @@ -3065,7 +3063,7 @@ JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass)) { if (WhiteBoxAPI) { // Make sure that wbclass is loaded by the null classloader - InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(wbclass))); + InstanceKlass* ik = java_lang_Class::as_InstanceKlass(JNIHandles::resolve(wbclass)); Handle loader(THREAD, ik->class_loader()); if (loader.is_null()) { WhiteBox::register_methods(env, wbclass, thread, methods, sizeof(methods) / sizeof(methods[0])); diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index a7b468c57a3..7728643c640 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -1136,7 +1136,7 @@ oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle rtype = T_OBJECT; } - InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(mirror)); + InstanceKlass* klass = java_lang_Class::as_InstanceKlass(mirror); Method* m = klass->method_with_idnum(slot); if (m == nullptr) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "invoke"); @@ -1153,7 +1153,7 @@ oop Reflection::invoke_constructor(oop constructor_mirror, objArrayHandle args, bool override = java_lang_reflect_Constructor::override(constructor_mirror) != 0; objArrayHandle ptypes(THREAD, objArrayOop(java_lang_reflect_Constructor::parameter_types(constructor_mirror))); - InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(mirror)); + InstanceKlass* klass = java_lang_Class::as_InstanceKlass(mirror); Method* m = klass->method_with_idnum(slot); if (m == nullptr) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "invoke"); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index b7ad8081c52..2f7161ff744 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -881,8 +881,8 @@ void SharedRuntime::throw_StackOverflowError_common(JavaThread* current, bool de // We avoid using the normal exception construction in this case because // it performs an upcall to Java, and we're already out of stack space. JavaThread* THREAD = current; // For exception macros. - Klass* k = vmClasses::StackOverflowError_klass(); - oop exception_oop = InstanceKlass::cast(k)->allocate_instance(CHECK); + InstanceKlass* k = vmClasses::StackOverflowError_klass(); + oop exception_oop = k->allocate_instance(CHECK); if (delayed) { java_lang_Throwable::set_message(exception_oop, Universe::delayed_stack_overflow_error_message()); From 90e81c2bee86f404250fb9b833d43b18190b5272 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Tue, 16 Sep 2025 01:11:04 +0000 Subject: [PATCH 0059/1116] 8367616: RISC-V: Auto-enable Zicboz extension for debug builds Reviewed-by: fyang, fjiang --- src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index 3d771123f12..3e5fb4610de 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -191,6 +191,9 @@ void RiscvHwprobe::add_features_from_query_result() { VM_Version::ext_Zbs.enable_feature(); } #ifndef PRODUCT + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZICBOZ)) { + VM_Version::ext_Zicboz.enable_feature(); + } if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBKB)) { VM_Version::ext_Zbkb.enable_feature(); } From 0fbae8050b6f853053c7dee6a43d3ffbcfa69954 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 16 Sep 2025 04:42:50 +0000 Subject: [PATCH 0060/1116] 8252582: HotSpot Style Guide should permit variable templates Reviewed-by: dholmes, stefank, kvn --- doc/hotspot-style.html | 45 +++++++++++++++++++++++------------------- doc/hotspot-style.md | 33 +++++++++++++++++-------------- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index fb4cffc9d43..7be6867b3ca 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -86,8 +86,9 @@ values
  • thread_local
  • nullptr
  • <atomic>
  • -
  • Inline -Variables
  • +
  • Variable Templates and +Inline Variables
  • Initializing variables with static storage duration
  • @@ -937,12 +938,18 @@ differ from what the Java compilers implement.

    "conservative" memory ordering, which may differ from (may be stronger than) sequentially consistent. There are algorithms in HotSpot that are believed to rely on that ordering.

    -

    Inline Variables

    -

    Variables with static storage duration may be declared -inline (p0386r2). -This has similar effects as for declaring a function inline: it can be -defined, identically, in multiple translation units, must be defined in -every translation unit in which it is Variable Templates and +Inline Variables +

    The use of variable templates (including static data member +templates) (N3651) is permitted. +They provide parameterized variables and constants in a simple and +direct form, instead of requiring the use of various workarounds.

    +

    Variables with static storage duration and variable templates may be +declared inline (p0386r2), and this usage is +permitted. This has similar effects as for declaring a function inline: +it can be defined, identically, in multiple translation units, must be +defined in every translation unit in which it is ODR used, and the behavior of the program is as if there is exactly one variable.

    @@ -955,16 +962,17 @@ initializations can make initialization order problems worse. The few ordering constraints that exist for non-inline variables don't apply, as there isn't a single program-designated translation unit containing the definition.

    -

    A constexpr static data member is implicitly -inline. As a consequence, an A constexpr static data member or static data member +template is implicitly inline. As a consequence, an ODR use of such a variable doesn't -require a definition in some .cpp file. (This is a change from -pre-C++17. Beginning with C++17, such a definition is considered a -duplicate definition, and is deprecated.)

    -

    Declaring a thread_local variable inline is -forbidden for HotSpot code. The use of -thread_local is already heavily restricted.

    +title="One Definition Rule">ODR use of such a member doesn't require +a definition in some .cpp file. (This is a change from pre-C++17. +Beginning with C++17, such a definition is considered a duplicate +definition, and is deprecated.)

    +

    Declaring a thread_local variable template or +inline variable is forbidden in HotSpot code. The use of thread_local is already +heavily restricted.

    Initializing variables with static storage duration

    @@ -1853,9 +1861,6 @@ Features