From a6885a2432b7decfaaa87a64b6889c901b710664 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 4 Dec 2025 17:54:57 +0100 Subject: [PATCH 01/12] wip --- src/hotspot/share/ci/ciArray.cpp | 7 +- src/hotspot/share/ci/ciArray.hpp | 2 +- src/hotspot/share/ci/ciArrayKlass.hpp | 4 +- src/hotspot/share/ci/ciClassList.hpp | 1 + src/hotspot/share/ci/ciField.cpp | 4 +- src/hotspot/share/ci/ciFlatArray.cpp | 111 ++++++++++++++++++ src/hotspot/share/ci/ciFlatArray.hpp | 12 ++ src/hotspot/share/ci/ciObject.hpp | 2 + src/hotspot/share/oops/flatArrayOop.hpp | 2 + .../share/oops/flatArrayOop.inline.hpp | 15 +++ src/hotspot/share/opto/compile.cpp | 64 +++++++++- src/hotspot/share/opto/inlinetypenode.hpp | 1 + src/hotspot/share/opto/memnode.cpp | 27 +++++ src/hotspot/share/opto/type.cpp | 8 ++ .../c2/irTests/stable/StableRefFinalTest.java | 3 +- .../c2/irTests/stable/StableRefPlainTest.java | 6 +- 16 files changed, 257 insertions(+), 12 deletions(-) create mode 100644 src/hotspot/share/ci/ciFlatArray.cpp diff --git a/src/hotspot/share/ci/ciArray.cpp b/src/hotspot/share/ci/ciArray.cpp index e45258668ca..425123ffdbb 100644 --- a/src/hotspot/share/ci/ciArray.cpp +++ b/src/hotspot/share/ci/ciArray.cpp @@ -109,12 +109,13 @@ ciConstant ciArray::element_value(int index) { // Current value of an element at the specified offset. // Returns T_ILLEGAL if there is no element at the given offset. ciConstant ciArray::element_value_by_offset(intptr_t element_offset) { + // precond(!is_flat()); BasicType elembt = element_basic_type(); - intptr_t shift = exact_log2(type2aelembytes(elembt)); + intptr_t shift = exact_log2(type2aelembytes(elembt)); intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt); intptr_t index = (element_offset - header) >> shift; - intptr_t offset = header + ((intptr_t)index << shift); - if (offset != element_offset || index != (jint)index || index < 0 || index >= length()) { + intptr_t offset = header + ((intptr_t) index << shift); + if (offset != element_offset || index != (jint) index || index < 0 || index >= length()) { return ciConstant(); } return element_value((jint) index); diff --git a/src/hotspot/share/ci/ciArray.hpp b/src/hotspot/share/ci/ciArray.hpp index ae01682ca16..337d2b39dba 100644 --- a/src/hotspot/share/ci/ciArray.hpp +++ b/src/hotspot/share/ci/ciArray.hpp @@ -68,7 +68,7 @@ class ciArray : public ciObject { // Current value of an element at the specified offset. // Returns T_ILLEGAL if there is no element at the given offset. - ciConstant element_value_by_offset(intptr_t element_offset); + virtual ciConstant element_value_by_offset(intptr_t element_offset); // What kind of ciObject is this? bool is_array() { return true; } diff --git a/src/hotspot/share/ci/ciArrayKlass.hpp b/src/hotspot/share/ci/ciArrayKlass.hpp index bed653b1360..9d31b166a4a 100644 --- a/src/hotspot/share/ci/ciArrayKlass.hpp +++ b/src/hotspot/share/ci/ciArrayKlass.hpp @@ -49,8 +49,8 @@ class ciArrayKlass : public ciKlass { public: jint dimension() { return _dimension; } - ciType* element_type(); // JLS calls this the "component type" - ciType* base_element_type(); // JLS calls this the "element type" + ciType* element_type(); // JLS calls this the "component type", (T[] for T[][]) + ciType* base_element_type(); // JLS calls this the "element type", (T for T[][]) bool is_leaf_type(); // No subtypes of this array type. // What kind of vmObject is this? diff --git a/src/hotspot/share/ci/ciClassList.hpp b/src/hotspot/share/ci/ciClassList.hpp index 511e4dfb9b9..f5ca05e3443 100644 --- a/src/hotspot/share/ci/ciClassList.hpp +++ b/src/hotspot/share/ci/ciClassList.hpp @@ -108,6 +108,7 @@ friend class ciTypeEntries; \ friend class ciSpeculativeTrapData; \ friend class ciSymbol; \ friend class ciArray; \ +friend class ciFlatArray; \ friend class ciObjArray; \ friend class ciMetadata; \ friend class ciReplay; \ diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp index bcc6f0062f2..eeb435cc719 100644 --- a/src/hotspot/share/ci/ciField.cpp +++ b/src/hotspot/share/ci/ciField.cpp @@ -238,7 +238,7 @@ ciField::ciField(ciField* declared_field, ciField* subfield) { _signature = subfield->_signature; _type = subfield->_type; - _is_constant = declared_field->is_strict() && declared_field->is_final(); + _is_constant = (declared_field->is_strict() && declared_field->is_final()) || declared_field->is_constant(); _known_to_link_with_put = subfield->_known_to_link_with_put; _known_to_link_with_get = subfield->_known_to_link_with_get; _constant_value = ciConstant(); @@ -265,7 +265,7 @@ ciField::ciField(ciField* declared_field) { _signature = ciSymbols::bool_signature(); _type = ciType::make(T_BOOLEAN); - _is_constant = declared_field->is_strict() && declared_field->is_final(); + _is_constant = (declared_field->is_strict() && declared_field->is_final()) || declared_field->is_constant();; _known_to_link_with_put = nullptr; _known_to_link_with_get = nullptr; _constant_value = ciConstant(); diff --git a/src/hotspot/share/ci/ciFlatArray.cpp b/src/hotspot/share/ci/ciFlatArray.cpp new file mode 100644 index 00000000000..c63c33f6158 --- /dev/null +++ b/src/hotspot/share/ci/ciFlatArray.cpp @@ -0,0 +1,111 @@ +/* + * 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. + * + */ + +#include "ci/ciArray.hpp" +#include "ci/ciFlatArray.hpp" +#include "ci/ciConstant.hpp" +#include "ci/ciUtilities.inline.hpp" +#include "oops/oop.inline.hpp" + +ciConstant ciFlatArray::null_marker_of_element_by_offset_impl(arrayOop ary, int index) { + if (ary == nullptr) { + return ciConstant(); + } + assert(ary->is_array(), ""); + if (index < 0 || index >= ary->length()) { + return ciConstant(); + } + assert(ary->is_objArray(), ""); + flatArrayOop objary = (flatArrayOop) ary; + jboolean elem = objary->null_marker_of_obj_at(index); + return ciConstant(T_BOOLEAN, elem); +} + +ciConstant ciFlatArray::check_constant_null_marker_cache(int off) { + if (_constant_null_markers != nullptr) { + for (int i = 0; i < _constant_null_markers->length(); ++i) { + ConstantValue cached_val = _constant_null_markers->at(i); + if (cached_val.off() == off) { + return cached_val.value(); + } + } + } + return ciConstant(); +} + +void ciFlatArray::add_to_constant_null_marker_cache(int off, ciConstant val) { + assert(val.is_valid(), "value must be valid"); + assert(!check_constant_value_cache(off, val.basic_type()).is_valid(), "duplicate"); + if (_constant_null_markers == nullptr) { + Arena* arena = CURRENT_ENV->arena(); + _constant_null_markers = new (arena) GrowableArray(arena, 1, 0, ConstantValue()); + } + _constant_null_markers->append(ConstantValue(off, val)); +} + +// ------------------------------------------------------------------ +// ciArray::element_value +// +// Current value of an element. +// Returns T_ILLEGAL if there is no element at the given index. +ciConstant ciFlatArray::null_marker_of_element_by_index(int index) { + ciConstant value = check_constant_null_marker_cache(index); + if (value.is_valid()) { + return value; + } + GUARDED_VM_ENTRY( + value = null_marker_of_element_by_offset_impl(get_arrayOop(), index);) + add_to_constant_null_marker_cache(index, value); + return value; +} + +ciConstant ciFlatArray::null_marker_of_element_by_offset(intptr_t element_offset) { + BasicType elembt = element_basic_type(); + FlatArrayKlass* faklass; + GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());) + int lh = faklass->layout_helper(); + int shift = Klass::layout_helper_log2_element_size(lh); + intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt); + intptr_t index = (element_offset - header) >> shift; + intptr_t offset = header + (index << shift); + if (offset != element_offset || index != (jint) index || index < 0 || index >= length()) { + return ciConstant(); + } + return null_marker_of_element_by_index((jint) index); +} + +ciConstant ciFlatArray::element_value_by_offset(intptr_t element_offset) { + BasicType elembt = element_basic_type(); + FlatArrayKlass* faklass; + GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());) + int lh = faklass->layout_helper(); + int shift = Klass::layout_helper_log2_element_size(lh); + intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt); + intptr_t index = (element_offset - header) >> shift; + intptr_t offset = header + (index << shift); + if (offset != element_offset || index != (jint) index || index < 0 || index >= length()) { + return ciConstant(); + } + return element_value((jint) index); +} diff --git a/src/hotspot/share/ci/ciFlatArray.hpp b/src/hotspot/share/ci/ciFlatArray.hpp index ec4fb9d80df..16d76f5fef0 100644 --- a/src/hotspot/share/ci/ciFlatArray.hpp +++ b/src/hotspot/share/ci/ciFlatArray.hpp @@ -42,6 +42,18 @@ class ciFlatArray : public ciArray { public: bool is_flat() { return true; } + + // Current value of an element at the specified offset. + // Returns T_ILLEGAL if there is no element at the given offset. + ciConstant element_value_by_offset(intptr_t element_offset) override; + ciConstant null_marker_of_element_by_offset(intptr_t element_offset); + ciConstant null_marker_of_element_by_index(int index); +private: + ciConstant null_marker_of_element_by_offset_impl(arrayOop ary, int index); + ciConstant check_constant_null_marker_cache(int off); + void add_to_constant_null_marker_cache(int off, ciConstant val); + + GrowableArray* _constant_null_markers = nullptr; }; #endif // SHARE_VM_CI_CIFLATARRAY_HPP diff --git a/src/hotspot/share/ci/ciObject.hpp b/src/hotspot/share/ci/ciObject.hpp index 9b60639edb5..ffe7f4d7f7b 100644 --- a/src/hotspot/share/ci/ciObject.hpp +++ b/src/hotspot/share/ci/ciObject.hpp @@ -59,6 +59,7 @@ class ciObject : public ciBaseObject { jobject _handle; ciKlass* _klass; +protected: // Cache constant value lookups to ensure that consistent values are observed during compilation. class ConstantValue { private: @@ -73,6 +74,7 @@ class ciObject : public ciBaseObject { ciConstant value() const { return _value; } }; +private: GrowableArray* _constant_values = nullptr; protected: diff --git a/src/hotspot/share/oops/flatArrayOop.hpp b/src/hotspot/share/oops/flatArrayOop.hpp index 5c86397e706..85063f6de72 100644 --- a/src/hotspot/share/oops/flatArrayOop.hpp +++ b/src/hotspot/share/oops/flatArrayOop.hpp @@ -42,6 +42,8 @@ class flatArrayOopDesc : public objArrayOopDesc { inline oop obj_at(int index) const; inline oop obj_at(int index, TRAPS) const; + inline jboolean null_marker_of_obj_at(int index) const; + inline jboolean null_marker_of_obj_at(int index, TRAPS) const; inline void obj_at_put(int index, oop value); inline void obj_at_put(int index, oop value, TRAPS); diff --git a/src/hotspot/share/oops/flatArrayOop.inline.hpp b/src/hotspot/share/oops/flatArrayOop.inline.hpp index 603e9a89144..ba1bef22184 100644 --- a/src/hotspot/share/oops/flatArrayOop.inline.hpp +++ b/src/hotspot/share/oops/flatArrayOop.inline.hpp @@ -65,6 +65,21 @@ inline oop flatArrayOopDesc::obj_at(int index, TRAPS) const { return res; } +inline jboolean flatArrayOopDesc::null_marker_of_obj_at(int index) const { + EXCEPTION_MARK; + return null_marker_of_obj_at(index, THREAD); +} + +inline jboolean flatArrayOopDesc::null_marker_of_obj_at(int index, TRAPS) const { + assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); + FlatArrayKlass* faklass = FlatArrayKlass::cast(klass()); + InlineKlass* vk = InlineKlass::cast(faklass->element_klass()); + char* this_oop = (char*) (oopDesc*) this; + char* val = (char*) value_at_addr(index, faklass->layout_helper()); + ptrdiff_t offset = val - this_oop + (ptrdiff_t)vk->null_marker_offset_in_payload(); + return bool_field(offset); +} + inline void flatArrayOopDesc::obj_at_put(int index, oop value) { EXCEPTION_MARK; // What if the caller is not a Java Thread? obj_at_put(index, value, THREAD); diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 4256923a695..aaf20a5be3a 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -54,6 +54,8 @@ #include "opto/cfgnode.hpp" #include "opto/chaitin.hpp" #include "opto/compile.hpp" + +#include "ci/ciFlatArray.hpp" #include "opto/connode.hpp" #include "opto/convertnode.hpp" #include "opto/divnode.hpp" @@ -2118,7 +2120,67 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { Node* n = _flat_access_nodes.at(i); assert(n != nullptr, "unexpected nullptr"); if (n->is_LoadFlat()) { - n->as_LoadFlat()->expand_atomic(igvn); + LoadFlatNode* loadn = n->as_LoadFlat(); + const ciInlineKlass* vk = loadn->vk(); + + const Type* base_type = igvn.type(loadn->base()); + const TypeOopPtr* oopptr = base_type->isa_oopptr(); + ciObject* oop = oopptr->const_oop(); + ciInstance* holder = oop->is_instance() ? oop->as_instance() : nullptr; + ciArray* array = oop->is_array() ? oop->as_array() : nullptr; + int off = igvn.type(loadn->ptr())->isa_ptr()->offset(); + if (UseNewCode) { + tty->print_cr("\n\n<><><><><><><><><><><><><><><><><><><><>"); + tty->print("- base_type : (%p) ", base_type); if (base_type != nullptr) base_type->dump(); tty->print_cr(""); tty->flush(); + tty->print("- oopptr : (%p) ", oopptr); if (oopptr != nullptr) oopptr->dump(); tty->print_cr(""); tty->flush(); + tty->print("- oop : (%p) ", oop); if (oop != nullptr) oop->print(); tty->print_cr(""); tty->flush(); + tty->print("- holder : (%p) ", holder); if (holder != nullptr) holder->print(); tty->print_cr(""); tty->flush(); + tty->print("- array : (%p) ", array); if (array != nullptr) array->print(); tty->print_cr(""); tty->flush(); + tty->print("- off : %d", off); tty->print_cr(""); tty->flush(); + } + + bool non_atomic_is_fine = false; + if (holder != nullptr) { + ciKlass* klass = holder->klass(); + ciInstanceKlass* iklass = klass->as_instance_klass(); + ciField* field = iklass->get_non_flat_field_by_offset(off); + // instead of field->null_marker_offset(): + // int nm_offset = off + vk->null_marker_offset_in_payload(); + ciField* nm_field = iklass->get_field_by_offset(field->null_marker_offset(), false); + ciConstant cst = holder->field_value(nm_field); + if (UseNewCode) { + tty->print("- klass : (%p) ", klass); if (klass != nullptr) klass->print(); tty->print_cr(""); tty->flush(); + tty->print("- field : (%p) ", field); if (field != nullptr) field->print(); tty->print_cr(""); tty->flush(); + tty->print("- nm_field : (%p) ", nm_field); if (nm_field != nullptr) nm_field->print(); tty->print_cr(""); tty->flush(); + tty->print("- cst : "); cst.print(); tty->print_cr(""); tty->flush(); + } + non_atomic_is_fine = FoldStableValues && field->is_stable() && cst.is_valid() && cst.as_boolean(); + } + if (array != nullptr) { + const TypeAryPtr* aryptr = oopptr->is_aryptr(); + //ciFlatArrayKlass* klass = array->klass()->as_flat_array_klass(); + //ciConstant elt = array->element_value_by_offset(off); + ciConstant elt = ((ciFlatArray*)array)->null_marker_of_element_by_offset(off); + // ciType* elt_type = array->element_type(); + // array->get_arrayOop(); + if (UseNewCode) { + tty->print("- aryptr : (%p) ", aryptr); if (aryptr != nullptr) aryptr->dump(); tty->print_cr(""); tty->flush(); + // tty->print("- klass : (%p) ", klass); if (klass != nullptr) klass->print(); tty->print_cr(""); tty->flush(); + tty->print("- elt : "); elt.print(); tty->print_cr(""); tty->flush(); + // tty->print("- elt_type : "); elt_type->print(); tty->print_cr(""); tty->flush(); + } + non_atomic_is_fine = FoldStableValues && aryptr->is_stable() && !elt.is_null_or_zero(); + } + + if (UseNewCode) { + tty->print_cr("[][][][][][][][][][][][][][][][][][][][]"); + } + + if (non_atomic_is_fine) { + n->as_LoadFlat()->expand_non_atomic(igvn); + } else { + n->as_LoadFlat()->expand_atomic(igvn); + } } else { n->as_StoreFlat()->expand_atomic(igvn); } diff --git a/src/hotspot/share/opto/inlinetypenode.hpp b/src/hotspot/share/opto/inlinetypenode.hpp index 308433e29a1..cb2b09c0e75 100644 --- a/src/hotspot/share/opto/inlinetypenode.hpp +++ b/src/hotspot/share/opto/inlinetypenode.hpp @@ -191,6 +191,7 @@ class LoadFlatNode final : public SafePointNode { Node* ptr() const { return in(TypeFunc::Parms + 1); } bool expand_non_atomic(PhaseIterGVN& igvn); void expand_atomic(PhaseIterGVN& igvn); + const ciInlineKlass* vk() const { return _vk; }; private: LoadFlatNode(ciInlineKlass* vk, const TypeTuple* type, bool null_free, DecoratorSet decorators) diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 2e9af662eb9..5242f1fce2e 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -2163,6 +2163,10 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { int off = tp->offset(); assert(off != Type::OffsetTop, "case covered by TypePtr::empty"); Compile* C = phase->C; + if (UseNewCode) { + tty->print_cr("tp->base(): %d", tp->base()); + tty->print_cr("off: %d", off); + } // If we are loading from a freshly-allocated object, produce a zero, // if the load is provably beyond the header of the object. @@ -2266,12 +2270,35 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { const TypeInstPtr* tinst = tp->is_instptr(); BasicType bt = value_basic_type(); + if (UseNewCode) { + tty->print("tinst: "); + tinst->dump(); + tty->print_cr(""); + tty->print_cr("bt: %d", bt); + } // Optimize loads from constant fields. ciObject* const_oop = tinst->const_oop(); + if (UseNewCode) { + tty->print_cr("const_oop: %p", const_oop); + if (const_oop != nullptr) { + tty->print("const_oop: "); + const_oop->print(); + tty->print_cr(""); + } + tty->print_cr("is_mismatched_access: %d", is_mismatched_access()); + } if (!is_mismatched_access() && off != Type::OffsetBot && const_oop != nullptr && const_oop->is_instance()) { const Type* con_type = Type::make_constant_from_field(const_oop->as_instance(), off, is_unsigned(), bt); + if (UseNewCode) { + tty->print_cr("con_type: %p", con_type); + } if (con_type != nullptr) { + if (UseNewCode) { + tty->print("con_type: "); + con_type->dump(); + tty->print_cr(""); + } return con_type; } } diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 8e8cd0fe801..f64662113b6 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -404,9 +404,17 @@ const Type* Type::make_constant_from_field(ciInstance* holder, int off, bool is_ // Instance field field = holder->klass()->as_instance_klass()->get_field_by_offset(off, /*is_static=*/false); } + if (UseNewCode) { + tty->print_cr("field: %p", field); + } if (field == nullptr) { return nullptr; // Wrong offset } + if (UseNewCode) { + tty->print("field: "); + field->print(); + tty->print_cr(""); + } return Type::make_constant_from_field(field, holder, loadbt, is_unsigned_load); } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java index 405c86a5fc9..2053f578b40 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java @@ -71,7 +71,8 @@ public Carrier(boolean init) { @Test @IR(counts = { IRNode.LOAD, ">0" }) - @IR(failOn = { IRNode.MEMBAR }) + @IR(applyIf = {"enable-valhalla", "false"}, failOn = { IRNode.MEMBAR }) + @IR(applyIf = {"enable-valhalla", "true"}, counts = { IRNode.MEMBAR, ">0" }) static int testNoFold() { // Access should not be folded. // No barriers expected for plain fields. diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java index bd5be32459d..4c196e24e56 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java @@ -78,7 +78,8 @@ public void init() { @Test @IR(counts = { IRNode.LOAD, ">0" }) - @IR(failOn = { IRNode.MEMBAR }) + @IR(applyIf = {"enable-valhalla", "false"}, failOn = { IRNode.MEMBAR }) + @IR(applyIf = {"enable-valhalla", "true"}, counts = { IRNode.MEMBAR, ">0" }) static int testNoFold() { // Access should not be folded. // No barriers expected for plain fields. @@ -109,7 +110,8 @@ static Carrier testConstructorFullInit() { } @Test - @IR(failOn = { IRNode.MEMBAR }) + @IR(applyIf = {"enable-valhalla", "false"}, failOn = { IRNode.MEMBAR }) + @IR(applyIf = {"enable-valhalla", "true"}, counts = { IRNode.MEMBAR, ">0" }) static void testMethodInit() { // Reference inits do not have membars. INIT_CARRIER.init(); From 1c7d4dfbbcae34def6a4007b03320c7ff77d9607 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Fri, 5 Dec 2025 19:36:38 +0100 Subject: [PATCH 02/12] More --- src/hotspot/share/ci/ciClassList.hpp | 1 + src/hotspot/share/ci/ciFlatArray.cpp | 77 ++++++++++++++++++++++++++++ src/hotspot/share/ci/ciFlatArray.hpp | 7 ++- src/hotspot/share/ci/ciInstance.cpp | 14 +++++ src/hotspot/share/ci/ciInstance.hpp | 1 + src/hotspot/share/ci/ciObject.hpp | 5 ++ src/hotspot/share/opto/memnode.cpp | 6 +-- src/hotspot/share/opto/type.cpp | 33 +++++++++++- src/hotspot/share/opto/type.hpp | 1 + 9 files changed, 137 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/ci/ciClassList.hpp b/src/hotspot/share/ci/ciClassList.hpp index f5ca05e3443..d812d96d119 100644 --- a/src/hotspot/share/ci/ciClassList.hpp +++ b/src/hotspot/share/ci/ciClassList.hpp @@ -53,6 +53,7 @@ class ciMethodType; class ciArray; class ciObjArray; class ciTypeArray; +class ciFlatArray; class ciSymbol; class ciMetadata; class ciMethod; diff --git a/src/hotspot/share/ci/ciFlatArray.cpp b/src/hotspot/share/ci/ciFlatArray.cpp index c63c33f6158..14a26ff52f7 100644 --- a/src/hotspot/share/ci/ciFlatArray.cpp +++ b/src/hotspot/share/ci/ciFlatArray.cpp @@ -23,7 +23,9 @@ */ #include "ci/ciArray.hpp" +#include "ci/ciField.hpp" #include "ci/ciFlatArray.hpp" +#include "ci/ciInlineKlass.hpp" #include "ci/ciConstant.hpp" #include "ci/ciUtilities.inline.hpp" #include "oops/oop.inline.hpp" @@ -109,3 +111,78 @@ ciConstant ciFlatArray::element_value_by_offset(intptr_t element_offset) { } return element_value((jint) index); } + +ciConstant ciFlatArray::field_value_by_offset(intptr_t field_offset) { + ciInlineKlass* elt_type = element_type()->as_inline_klass(); + BasicType elt_basic_type = element_basic_type(); tty->print_cr(""); tty->flush(); + FlatArrayKlass* faklass; + GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());) + int lh = faklass->layout_helper(); + int shift = Klass::layout_helper_log2_element_size(lh); + intptr_t header = arrayOopDesc::base_offset_in_bytes(elt_basic_type); + intptr_t index = (field_offset - header) >> shift; + intptr_t element_offset = header + (index << shift); + int field_offset_in_element = (int)(field_offset - element_offset); + ciField* field = elt_type->get_field_by_offset(elt_type->payload_offset() + field_offset_in_element, false); + if (field == nullptr) { + if (field_offset_in_element != elt_type->null_marker_offset_in_payload()) { + return ciConstant(); + } + } + + if (UseNewCode) { + tty->print_cr("\n\n{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}"); + tty->print("elt_type: "); elt_type->print(); tty->print_cr(""); tty->flush(); + tty->print("shift: %d", shift); tty->print_cr(""); tty->flush(); + tty->print("header: %ld", header); tty->print_cr(""); tty->flush(); + tty->print("index: %ld", index); tty->print_cr(""); tty->flush(); + tty->print("element_offset: %ld", element_offset); tty->print_cr(""); tty->flush(); + tty->print("field_offset_in_element: %d", field_offset_in_element); tty->print_cr(""); tty->flush(); + + for (int i = 0; i < elt_type->nof_nonstatic_fields(); ++i) { + tty->print("field (%d): ", i); elt_type->nonstatic_field_at(i)->print(); tty->print_cr(""); tty->flush(); + } + + tty->print("field: (%p) ", field); if (field != nullptr) field->print(); tty->print_cr(""); tty->flush(); + } + + if (index != (jint) index || index < 0 || index >= length()) { + return ciConstant(); + } + ciConstant elt = field_value((jint) index, field); + + if (UseNewCode) { + tty->print("elt: "); elt.print(); tty->print_cr(""); tty->flush(); + tty->print_cr("[][][][][][][][][][][][][][][][][][][][]"); + } + + return elt; +} + +ciConstant ciFlatArray::field_value(int index, ciField* field) { + BasicType elembt = element_basic_type(); + ciConstant value = check_constant_value_cache(index, elembt); + if (value.is_valid()) { + if (UseNewCode) { + tty->print("value: "); value.print(); tty->print_cr(""); tty->flush(); + } + if (field == nullptr) { + return value.as_object()->as_instance()->null_marker_value(); + } + return value.as_object()->as_instance()->field_value(field); + } + GUARDED_VM_ENTRY( + value = element_value_impl(T_OBJECT, get_arrayOop(), index); + ) + + if (UseNewCode) { + tty->print("value: "); value.print(); tty->print_cr(""); tty->flush(); + } + add_to_constant_value_cache(index, value); + + if (field == nullptr) { + return value.as_object()->as_instance()->null_marker_value(); + } + return value.as_object()->as_instance()->field_value(field); +} + diff --git a/src/hotspot/share/ci/ciFlatArray.hpp b/src/hotspot/share/ci/ciFlatArray.hpp index 16d76f5fef0..1bac91df8c4 100644 --- a/src/hotspot/share/ci/ciFlatArray.hpp +++ b/src/hotspot/share/ci/ciFlatArray.hpp @@ -41,17 +41,22 @@ class ciFlatArray : public ciArray { const char* type_string() { return "ciFlatArray"; } public: - bool is_flat() { return true; } + bool is_flat_array() const override { return true; } + bool is_flat() override { return true; } // Current value of an element at the specified offset. // Returns T_ILLEGAL if there is no element at the given offset. ciConstant element_value_by_offset(intptr_t element_offset) override; + ciConstant field_value_by_offset(intptr_t field_offset); + ciConstant field_value(int index, ciField* field); ciConstant null_marker_of_element_by_offset(intptr_t element_offset); ciConstant null_marker_of_element_by_index(int index); + private: ciConstant null_marker_of_element_by_offset_impl(arrayOop ary, int index); ciConstant check_constant_null_marker_cache(int off); void add_to_constant_null_marker_cache(int off, ciConstant val); + //ciConstant element_value_impl(arrayOop ary, int index, int offset); GrowableArray* _constant_null_markers = nullptr; }; diff --git a/src/hotspot/share/ci/ciInstance.cpp b/src/hotspot/share/ci/ciInstance.cpp index 49581db487a..929ef6935e5 100644 --- a/src/hotspot/share/ci/ciInstance.cpp +++ b/src/hotspot/share/ci/ciInstance.cpp @@ -25,6 +25,8 @@ #include "ci/ciConstant.hpp" #include "ci/ciField.hpp" #include "ci/ciInstance.hpp" + +#include "ciInlineKlass.hpp" #include "ci/ciInstanceKlass.hpp" #include "ci/ciNullObject.hpp" #include "ci/ciUtilities.inline.hpp" @@ -100,6 +102,18 @@ ciConstant ciInstance::field_value_impl(BasicType field_btype, int offset) { return value; } +// ------------------------------------------------------------------ +// ciInstance::null_marker_value +// +// Constant value of the null marker. +ciConstant ciInstance::null_marker_value() { + if (!klass()->is_inlinetype()) { + return ciConstant(); + } + ciInlineKlass* ik = klass()->as_inline_klass(); + return field_value_impl(T_BOOLEAN, ik->null_marker_offset_in_payload() + ik->payload_offset()); +} + // ------------------------------------------------------------------ // ciInstance::field_value // diff --git a/src/hotspot/share/ci/ciInstance.hpp b/src/hotspot/share/ci/ciInstance.hpp index 1fb09985930..5877debebd2 100644 --- a/src/hotspot/share/ci/ciInstance.hpp +++ b/src/hotspot/share/ci/ciInstance.hpp @@ -65,6 +65,7 @@ class ciInstance : public ciObject { // Constant value of a field at the specified offset. ciConstant field_value_by_offset(int field_offset); + ciConstant null_marker_value(); ciKlass* java_lang_Class_klass(); char* java_lang_String_str(char* buf, size_t buflen); diff --git a/src/hotspot/share/ci/ciObject.hpp b/src/hotspot/share/ci/ciObject.hpp index ffe7f4d7f7b..c0b0a8c67ba 100644 --- a/src/hotspot/share/ci/ciObject.hpp +++ b/src/hotspot/share/ci/ciObject.hpp @@ -130,6 +130,7 @@ class ciObject : public ciBaseObject { virtual bool is_array() { return false; } virtual bool is_obj_array() { return false; } virtual bool is_type_array() { return false; } + virtual bool is_flat_array() const { return false; } virtual bool is_native_entry_point()const { return false; } // Is this a type or value which has no associated class? @@ -184,6 +185,10 @@ class ciObject : public ciBaseObject { assert(is_type_array(), "bad cast"); return (ciTypeArray*)this; } + ciFlatArray* as_flat_array() { + assert(is_flat_array(), "bad cast"); + return (ciFlatArray*)this; + } // Print debugging output about this ciObject. void print(outputStream* st); diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 5242f1fce2e..d69ea2a866c 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -2163,10 +2163,6 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { int off = tp->offset(); assert(off != Type::OffsetTop, "case covered by TypePtr::empty"); Compile* C = phase->C; - if (UseNewCode) { - tty->print_cr("tp->base(): %d", tp->base()); - tty->print_cr("off: %d", off); - } // If we are loading from a freshly-allocated object, produce a zero, // if the load is provably beyond the header of the object. @@ -2199,7 +2195,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { ciObject* aobj = ary->const_oop(); if (aobj != nullptr && off_beyond_header && adr->is_AddP() && off != Type::OffsetBot) { int stable_dimension = (ary->stable_dimension() > 0 ? ary->stable_dimension() - 1 : 0); - const Type* con_type = Type::make_constant_from_array_element(aobj->as_array(), off, + const Type* con_type = Type::make_constant_from_array_element(aobj->as_array(), off, ary->field_offset().get(), stable_dimension, value_basic_type(), is_unsigned()); if (con_type != nullptr) { diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index f64662113b6..ac93950a7ed 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -23,6 +23,7 @@ */ #include "ci/ciField.hpp" +#include "ci/ciFlatArray.hpp" #include "ci/ciFlatArrayKlass.hpp" #include "ci/ciInlineKlass.hpp" #include "ci/ciMethodData.hpp" @@ -373,8 +374,7 @@ static ciConstant check_mismatched_access(ciConstant con, BasicType loadbt, bool return ciConstant(); // T_ILLEGAL } -// Try to constant-fold a stable array element. -const Type* Type::make_constant_from_array_element(ciArray* array, int off, int stable_dimension, +static const Type* make_constant_from_non_flat_array_element(ciArray* array, int off, int stable_dimension, BasicType loadbt, bool is_unsigned_load) { // Decode the results of GraphKit::array_element_address. ciConstant element_value = array->element_value_by_offset(off); @@ -383,6 +383,26 @@ const Type* Type::make_constant_from_array_element(ciArray* array, int off, int } ciConstant con = check_mismatched_access(element_value, loadbt, is_unsigned_load); + assert(con.basic_type() != T_ILLEGAL, "elembt=%s; loadbt=%s; unsigned=%d", + type2name(element_value.basic_type()), type2name(loadbt), is_unsigned_load); + + if (con.is_valid() && // not a mismatched access + !con.is_null_or_zero()) { // not a default value + bool is_narrow_oop = (loadbt == T_NARROWOOP); + return Type::make_from_constant(con, /*require_constant=*/true, stable_dimension, is_narrow_oop, /*is_autobox_cache=*/false); + } + return nullptr; +} + +static const Type* make_constant_from_flat_array_element(ciFlatArray* array, int off, int field_offset, int stable_dimension, + BasicType loadbt, bool is_unsigned_load) { + // Decode the results of GraphKit::array_element_address. + ciConstant element_value = array->field_value_by_offset(off + field_offset); + if (element_value.basic_type() == T_ILLEGAL) { + return nullptr; // wrong offset + } + ciConstant con = check_mismatched_access(element_value, loadbt, is_unsigned_load); + assert(con.basic_type() != T_ILLEGAL, "elembt=%s; loadbt=%s; unsigned=%d", type2name(element_value.basic_type()), type2name(loadbt), is_unsigned_load); @@ -394,6 +414,15 @@ const Type* Type::make_constant_from_array_element(ciArray* array, int off, int return nullptr; } +// Try to constant-fold a stable array element. +const Type* Type::make_constant_from_array_element(ciArray* array, int off, int field_offset, int stable_dimension, + BasicType loadbt, bool is_unsigned_load) { + if (array->is_flat()) { + return make_constant_from_flat_array_element(array->as_flat_array(), off, field_offset, stable_dimension, loadbt, is_unsigned_load); + } + return make_constant_from_non_flat_array_element(array, off, stable_dimension, loadbt, is_unsigned_load); +} + const Type* Type::make_constant_from_field(ciInstance* holder, int off, bool is_unsigned_load, BasicType loadbt) { ciField* field; ciType* type = holder->java_mirror_type(); diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 52b73b8f67c..e6999aad2a6 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -509,6 +509,7 @@ class Type { static const Type* make_constant_from_array_element(ciArray* array, int off, + int field_offset, int stable_dimension, BasicType loadbt, bool is_unsigned_load); From 79091092806acdd8324b6dbcba93c7db7326778b Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 11 Dec 2025 15:05:38 +0100 Subject: [PATCH 03/12] applyIf --- .../jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java index 027bd2dce30..11199c3c515 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java @@ -112,7 +112,8 @@ static int testNoFold() { @Test @IR(counts = { IRNode.LOAD, ">0" }) - @IR(failOn = { IRNode.MEMBAR }) + @IR(applyIf = {"enable-valhalla", "false"}, failOn = { IRNode.MEMBAR }) + @IR(applyIf = {"enable-valhalla", "true"}, counts = { IRNode.MEMBAR, "> 0" }) static int testPartialFold() { // Access should not be folded. // No barriers expected for plain fields. From 276b06f928cabafcf74bcdc6e64d7e6d2ca5a93d Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 11 Dec 2025 15:50:44 +0100 Subject: [PATCH 04/12] Fixes --- src/hotspot/share/ci/ciFlatArray.cpp | 2 +- src/hotspot/share/ci/ciFlatArray.hpp | 2 +- src/hotspot/share/ci/ciInstance.cpp | 3 +-- src/hotspot/share/opto/compile.cpp | 9 +++++++-- src/hotspot/share/opto/memnode.cpp | 8 ++++++++ 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/ci/ciFlatArray.cpp b/src/hotspot/share/ci/ciFlatArray.cpp index 14a26ff52f7..122eb2c999c 100644 --- a/src/hotspot/share/ci/ciFlatArray.cpp +++ b/src/hotspot/share/ci/ciFlatArray.cpp @@ -23,10 +23,10 @@ */ #include "ci/ciArray.hpp" +#include "ci/ciConstant.hpp" #include "ci/ciField.hpp" #include "ci/ciFlatArray.hpp" #include "ci/ciInlineKlass.hpp" -#include "ci/ciConstant.hpp" #include "ci/ciUtilities.inline.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/share/ci/ciFlatArray.hpp b/src/hotspot/share/ci/ciFlatArray.hpp index 1bac91df8c4..96b5b4957ec 100644 --- a/src/hotspot/share/ci/ciFlatArray.hpp +++ b/src/hotspot/share/ci/ciFlatArray.hpp @@ -38,7 +38,7 @@ class ciFlatArray : public ciArray { protected: ciFlatArray(flatArrayHandle h_o) : ciArray(h_o) {} - const char* type_string() { return "ciFlatArray"; } + const char* type_string() override { return "ciFlatArray"; } public: bool is_flat_array() const override { return true; } diff --git a/src/hotspot/share/ci/ciInstance.cpp b/src/hotspot/share/ci/ciInstance.cpp index 929ef6935e5..5487ded8dbf 100644 --- a/src/hotspot/share/ci/ciInstance.cpp +++ b/src/hotspot/share/ci/ciInstance.cpp @@ -24,9 +24,8 @@ #include "ci/ciConstant.hpp" #include "ci/ciField.hpp" +#include "ci/ciInlineKlass.hpp" #include "ci/ciInstance.hpp" - -#include "ciInlineKlass.hpp" #include "ci/ciInstanceKlass.hpp" #include "ci/ciNullObject.hpp" #include "ci/ciUtilities.inline.hpp" diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index aaf20a5be3a..537b1c7565b 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -24,6 +24,7 @@ #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "ci/ciFlatArray.hpp" #include "ci/ciReplay.hpp" #include "classfile/javaClasses.hpp" #include "code/aotCodeCache.hpp" @@ -54,8 +55,6 @@ #include "opto/cfgnode.hpp" #include "opto/chaitin.hpp" #include "opto/compile.hpp" - -#include "ci/ciFlatArray.hpp" #include "opto/connode.hpp" #include "opto/convertnode.hpp" #include "opto/divnode.hpp" @@ -2129,6 +2128,7 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { ciInstance* holder = oop->is_instance() ? oop->as_instance() : nullptr; ciArray* array = oop->is_array() ? oop->as_array() : nullptr; int off = igvn.type(loadn->ptr())->isa_ptr()->offset(); +#ifndef PRODUCT if (UseNewCode) { tty->print_cr("\n\n<><><><><><><><><><><><><><><><><><><><>"); tty->print("- base_type : (%p) ", base_type); if (base_type != nullptr) base_type->dump(); tty->print_cr(""); tty->flush(); @@ -2138,6 +2138,7 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { tty->print("- array : (%p) ", array); if (array != nullptr) array->print(); tty->print_cr(""); tty->flush(); tty->print("- off : %d", off); tty->print_cr(""); tty->flush(); } +#endif bool non_atomic_is_fine = false; if (holder != nullptr) { @@ -2149,10 +2150,12 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { ciField* nm_field = iklass->get_field_by_offset(field->null_marker_offset(), false); ciConstant cst = holder->field_value(nm_field); if (UseNewCode) { +#ifndef PRODUCT tty->print("- klass : (%p) ", klass); if (klass != nullptr) klass->print(); tty->print_cr(""); tty->flush(); tty->print("- field : (%p) ", field); if (field != nullptr) field->print(); tty->print_cr(""); tty->flush(); tty->print("- nm_field : (%p) ", nm_field); if (nm_field != nullptr) nm_field->print(); tty->print_cr(""); tty->flush(); tty->print("- cst : "); cst.print(); tty->print_cr(""); tty->flush(); +#endif } non_atomic_is_fine = FoldStableValues && field->is_stable() && cst.is_valid() && cst.as_boolean(); } @@ -2164,10 +2167,12 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { // ciType* elt_type = array->element_type(); // array->get_arrayOop(); if (UseNewCode) { +#ifndef PRODUCT tty->print("- aryptr : (%p) ", aryptr); if (aryptr != nullptr) aryptr->dump(); tty->print_cr(""); tty->flush(); // tty->print("- klass : (%p) ", klass); if (klass != nullptr) klass->print(); tty->print_cr(""); tty->flush(); tty->print("- elt : "); elt.print(); tty->print_cr(""); tty->flush(); // tty->print("- elt_type : "); elt_type->print(); tty->print_cr(""); tty->flush(); +#endif } non_atomic_is_fine = FoldStableValues && aryptr->is_stable() && !elt.is_null_or_zero(); } diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index d69ea2a866c..7e70d493c62 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -2267,15 +2267,18 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { const TypeInstPtr* tinst = tp->is_instptr(); BasicType bt = value_basic_type(); if (UseNewCode) { +#ifndef PRODUCT tty->print("tinst: "); tinst->dump(); tty->print_cr(""); tty->print_cr("bt: %d", bt); +#endif } // Optimize loads from constant fields. ciObject* const_oop = tinst->const_oop(); if (UseNewCode) { +#ifndef PRODUCT tty->print_cr("const_oop: %p", const_oop); if (const_oop != nullptr) { tty->print("const_oop: "); @@ -2283,17 +2286,22 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { tty->print_cr(""); } tty->print_cr("is_mismatched_access: %d", is_mismatched_access()); +#endif } if (!is_mismatched_access() && off != Type::OffsetBot && const_oop != nullptr && const_oop->is_instance()) { const Type* con_type = Type::make_constant_from_field(const_oop->as_instance(), off, is_unsigned(), bt); if (UseNewCode) { +#ifndef PRODUCT tty->print_cr("con_type: %p", con_type); +#endif } if (con_type != nullptr) { if (UseNewCode) { +#ifndef PRODUCT tty->print("con_type: "); con_type->dump(); tty->print_cr(""); +#endif } return con_type; } From fc8d78f980847c177d015d574f6ed9b19d2d3dd1 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 11 Dec 2025 16:17:38 +0100 Subject: [PATCH 05/12] segfault --- src/hotspot/share/opto/compile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 537b1c7565b..19b6c30b47d 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2125,8 +2125,8 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { const Type* base_type = igvn.type(loadn->base()); const TypeOopPtr* oopptr = base_type->isa_oopptr(); ciObject* oop = oopptr->const_oop(); - ciInstance* holder = oop->is_instance() ? oop->as_instance() : nullptr; - ciArray* array = oop->is_array() ? oop->as_array() : nullptr; + ciInstance* holder = oop != nullptr && oop->is_instance() ? oop->as_instance() : nullptr; + ciArray* array = oop != nullptr && oop->is_array() ? oop->as_array() : nullptr; int off = igvn.type(loadn->ptr())->isa_ptr()->offset(); #ifndef PRODUCT if (UseNewCode) { From 2d63ba870439a1a85eca6a2fb6a61797486fa155 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Fri, 12 Dec 2025 12:54:21 +0100 Subject: [PATCH 06/12] Segfault? --- src/hotspot/share/opto/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 19b6c30b47d..5d9d9fe5da5 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2148,7 +2148,7 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { // instead of field->null_marker_offset(): // int nm_offset = off + vk->null_marker_offset_in_payload(); ciField* nm_field = iklass->get_field_by_offset(field->null_marker_offset(), false); - ciConstant cst = holder->field_value(nm_field); + ciConstant cst = nm_field != nullptr ? holder->field_value(nm_field) : ciConstant() /* invalid */; if (UseNewCode) { #ifndef PRODUCT tty->print("- klass : (%p) ", klass); if (klass != nullptr) klass->print(); tty->print_cr(""); tty->flush(); From fee2e884f348ccbd35d4ad3d51db549ab4071f74 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Fri, 12 Dec 2025 16:14:43 +0100 Subject: [PATCH 07/12] damn is_null_or_zero assumes is_valid --- src/hotspot/share/ci/ciConstant.cpp | 1 + src/hotspot/share/opto/compile.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/ci/ciConstant.cpp b/src/hotspot/share/ci/ciConstant.cpp index 234cd8171c4..b59e6b5f8f8 100644 --- a/src/hotspot/share/ci/ciConstant.cpp +++ b/src/hotspot/share/ci/ciConstant.cpp @@ -33,6 +33,7 @@ // ------------------------------------------------------------------ // ciConstant::is_null_or_zero +// This assumes `this->is_valid()`, otherwise, `as_object` will assert. bool ciConstant::is_null_or_zero() const { if (!is_java_primitive(basic_type())) { return as_object()->is_null_object(); diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index c247082a76b..bd719415bfd 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2178,7 +2178,7 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { // tty->print("- elt_type : "); elt_type->print(); tty->print_cr(""); tty->flush(); #endif } - non_atomic_is_fine = FoldStableValues && aryptr->is_stable() && !elt.is_null_or_zero(); + non_atomic_is_fine = FoldStableValues && aryptr->is_stable() && elt.is_valid() && !elt.is_null_or_zero(); } if (UseNewCode) { From a2244c5f69350d66359657d63ca9448bcbb9415a Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Mon, 15 Dec 2025 14:40:08 +0100 Subject: [PATCH 08/12] Fix header size --- src/hotspot/share/ci/ciFlatArray.cpp | 7 ++++--- src/hotspot/share/opto/memnode.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/ci/ciFlatArray.cpp b/src/hotspot/share/ci/ciFlatArray.cpp index 122eb2c999c..3c4afbd1684 100644 --- a/src/hotspot/share/ci/ciFlatArray.cpp +++ b/src/hotspot/share/ci/ciFlatArray.cpp @@ -114,12 +114,11 @@ ciConstant ciFlatArray::element_value_by_offset(intptr_t element_offset) { ciConstant ciFlatArray::field_value_by_offset(intptr_t field_offset) { ciInlineKlass* elt_type = element_type()->as_inline_klass(); - BasicType elt_basic_type = element_basic_type(); tty->print_cr(""); tty->flush(); FlatArrayKlass* faklass; GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());) int lh = faklass->layout_helper(); int shift = Klass::layout_helper_log2_element_size(lh); - intptr_t header = arrayOopDesc::base_offset_in_bytes(elt_basic_type); + intptr_t header = arrayOopDesc::base_offset_in_bytes(T_FLAT_ELEMENT); intptr_t index = (field_offset - header) >> shift; intptr_t element_offset = header + (index << shift); int field_offset_in_element = (int)(field_offset - element_offset); @@ -132,6 +131,8 @@ ciConstant ciFlatArray::field_value_by_offset(intptr_t field_offset) { if (UseNewCode) { tty->print_cr("\n\n{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}"); + tty->print("this: "); this->print(); tty->print_cr(""); tty->flush(); + tty->print("field_offset: %ld", field_offset); tty->print_cr(""); tty->flush(); tty->print("elt_type: "); elt_type->print(); tty->print_cr(""); tty->flush(); tty->print("shift: %d", shift); tty->print_cr(""); tty->flush(); tty->print("header: %ld", header); tty->print_cr(""); tty->flush(); @@ -164,7 +165,7 @@ ciConstant ciFlatArray::field_value(int index, ciField* field) { ciConstant value = check_constant_value_cache(index, elembt); if (value.is_valid()) { if (UseNewCode) { - tty->print("value: "); value.print(); tty->print_cr(""); tty->flush(); + tty->print("cached value: "); value.print(); tty->print_cr(""); tty->flush(); } if (field == nullptr) { return value.as_object()->as_instance()->null_marker_value(); diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 40e1b115b6a..82530b5eacf 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -2262,7 +2262,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { const TypeInstPtr* tinst = tp->is_instptr(); BasicType bt = value_basic_type(); - if (UseNewCode) { + if (UseNewCode2) { #ifndef PRODUCT tty->print("tinst: "); tinst->dump(); @@ -2273,7 +2273,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { // Optimize loads from constant fields. ciObject* const_oop = tinst->const_oop(); - if (UseNewCode) { + if (UseNewCode2) { #ifndef PRODUCT tty->print_cr("const_oop: %p", const_oop); if (const_oop != nullptr) { @@ -2286,13 +2286,13 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { } if (!is_mismatched_access() && off != Type::OffsetBot && const_oop != nullptr && const_oop->is_instance()) { const Type* con_type = Type::make_constant_from_field(const_oop->as_instance(), off, is_unsigned(), bt); - if (UseNewCode) { + if (UseNewCode2) { #ifndef PRODUCT tty->print_cr("con_type: %p", con_type); #endif } if (con_type != nullptr) { - if (UseNewCode) { + if (UseNewCode2) { #ifndef PRODUCT tty->print("con_type: "); con_type->dump(); From 8b3346f2269735258de63c4e5fd6e8d3fed1b30f Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Tue, 16 Dec 2025 17:12:27 +0100 Subject: [PATCH 09/12] Cleanup --- src/hotspot/share/ci/ciArray.cpp | 7 ++-- src/hotspot/share/ci/ciFlatArray.cpp | 38 ++------------------- src/hotspot/share/opto/compile.cpp | 41 +---------------------- src/hotspot/share/opto/inlinetypenode.hpp | 1 - src/hotspot/share/opto/memnode.cpp | 31 ----------------- src/hotspot/share/opto/type.cpp | 8 ----- 6 files changed, 6 insertions(+), 120 deletions(-) diff --git a/src/hotspot/share/ci/ciArray.cpp b/src/hotspot/share/ci/ciArray.cpp index 425123ffdbb..e45258668ca 100644 --- a/src/hotspot/share/ci/ciArray.cpp +++ b/src/hotspot/share/ci/ciArray.cpp @@ -109,13 +109,12 @@ ciConstant ciArray::element_value(int index) { // Current value of an element at the specified offset. // Returns T_ILLEGAL if there is no element at the given offset. ciConstant ciArray::element_value_by_offset(intptr_t element_offset) { - // precond(!is_flat()); BasicType elembt = element_basic_type(); - intptr_t shift = exact_log2(type2aelembytes(elembt)); + intptr_t shift = exact_log2(type2aelembytes(elembt)); intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt); intptr_t index = (element_offset - header) >> shift; - intptr_t offset = header + ((intptr_t) index << shift); - if (offset != element_offset || index != (jint) index || index < 0 || index >= length()) { + intptr_t offset = header + ((intptr_t)index << shift); + if (offset != element_offset || index != (jint)index || index < 0 || index >= length()) { return ciConstant(); } return element_value((jint) index); diff --git a/src/hotspot/share/ci/ciFlatArray.cpp b/src/hotspot/share/ci/ciFlatArray.cpp index 3c4afbd1684..50c50997c40 100644 --- a/src/hotspot/share/ci/ciFlatArray.cpp +++ b/src/hotspot/share/ci/ciFlatArray.cpp @@ -66,9 +66,6 @@ void ciFlatArray::add_to_constant_null_marker_cache(int off, ciConstant val) { _constant_null_markers->append(ConstantValue(off, val)); } -// ------------------------------------------------------------------ -// ciArray::element_value -// // Current value of an element. // Returns T_ILLEGAL if there is no element at the given index. ciConstant ciFlatArray::null_marker_of_element_by_index(int index) { @@ -83,12 +80,11 @@ ciConstant ciFlatArray::null_marker_of_element_by_index(int index) { } ciConstant ciFlatArray::null_marker_of_element_by_offset(intptr_t element_offset) { - BasicType elembt = element_basic_type(); FlatArrayKlass* faklass; GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());) int lh = faklass->layout_helper(); int shift = Klass::layout_helper_log2_element_size(lh); - intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt); + intptr_t header = arrayOopDesc::base_offset_in_bytes(T_FLAT_ELEMENT); intptr_t index = (element_offset - header) >> shift; intptr_t offset = header + (index << shift); if (offset != element_offset || index != (jint) index || index < 0 || index >= length()) { @@ -98,12 +94,11 @@ ciConstant ciFlatArray::null_marker_of_element_by_offset(intptr_t element_offset } ciConstant ciFlatArray::element_value_by_offset(intptr_t element_offset) { - BasicType elembt = element_basic_type(); FlatArrayKlass* faklass; GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());) int lh = faklass->layout_helper(); int shift = Klass::layout_helper_log2_element_size(lh); - intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt); + intptr_t header = arrayOopDesc::base_offset_in_bytes(T_FLAT_ELEMENT); intptr_t index = (element_offset - header) >> shift; intptr_t offset = header + (index << shift); if (offset != element_offset || index != (jint) index || index < 0 || index >= length()) { @@ -129,34 +124,11 @@ ciConstant ciFlatArray::field_value_by_offset(intptr_t field_offset) { } } - if (UseNewCode) { - tty->print_cr("\n\n{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}"); - tty->print("this: "); this->print(); tty->print_cr(""); tty->flush(); - tty->print("field_offset: %ld", field_offset); tty->print_cr(""); tty->flush(); - tty->print("elt_type: "); elt_type->print(); tty->print_cr(""); tty->flush(); - tty->print("shift: %d", shift); tty->print_cr(""); tty->flush(); - tty->print("header: %ld", header); tty->print_cr(""); tty->flush(); - tty->print("index: %ld", index); tty->print_cr(""); tty->flush(); - tty->print("element_offset: %ld", element_offset); tty->print_cr(""); tty->flush(); - tty->print("field_offset_in_element: %d", field_offset_in_element); tty->print_cr(""); tty->flush(); - - for (int i = 0; i < elt_type->nof_nonstatic_fields(); ++i) { - tty->print("field (%d): ", i); elt_type->nonstatic_field_at(i)->print(); tty->print_cr(""); tty->flush(); - } - - tty->print("field: (%p) ", field); if (field != nullptr) field->print(); tty->print_cr(""); tty->flush(); - } - if (index != (jint) index || index < 0 || index >= length()) { return ciConstant(); } ciConstant elt = field_value((jint) index, field); - if (UseNewCode) { - tty->print("elt: "); elt.print(); tty->print_cr(""); tty->flush(); - tty->print_cr("[][][][][][][][][][][][][][][][][][][][]"); - } - return elt; } @@ -164,9 +136,6 @@ ciConstant ciFlatArray::field_value(int index, ciField* field) { BasicType elembt = element_basic_type(); ciConstant value = check_constant_value_cache(index, elembt); if (value.is_valid()) { - if (UseNewCode) { - tty->print("cached value: "); value.print(); tty->print_cr(""); tty->flush(); - } if (field == nullptr) { return value.as_object()->as_instance()->null_marker_value(); } @@ -176,9 +145,6 @@ ciConstant ciFlatArray::field_value(int index, ciField* field) { value = element_value_impl(T_OBJECT, get_arrayOop(), index); ) - if (UseNewCode) { - tty->print("value: "); value.print(); tty->print_cr(""); tty->flush(); - } add_to_constant_value_cache(index, value); if (field == nullptr) { diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index bd719415bfd..e4f52576524 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2124,7 +2124,6 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { assert(n != nullptr, "unexpected nullptr"); if (n->is_LoadFlat()) { LoadFlatNode* loadn = n->as_LoadFlat(); - const ciInlineKlass* vk = loadn->vk(); const Type* base_type = igvn.type(loadn->base()); const TypeOopPtr* oopptr = base_type->isa_oopptr(); @@ -2132,59 +2131,21 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { ciInstance* holder = oop != nullptr && oop->is_instance() ? oop->as_instance() : nullptr; ciArray* array = oop != nullptr && oop->is_array() ? oop->as_array() : nullptr; int off = igvn.type(loadn->ptr())->isa_ptr()->offset(); -#ifndef PRODUCT - if (UseNewCode) { - tty->print_cr("\n\n<><><><><><><><><><><><><><><><><><><><>"); - tty->print("- base_type : (%p) ", base_type); if (base_type != nullptr) base_type->dump(); tty->print_cr(""); tty->flush(); - tty->print("- oopptr : (%p) ", oopptr); if (oopptr != nullptr) oopptr->dump(); tty->print_cr(""); tty->flush(); - tty->print("- oop : (%p) ", oop); if (oop != nullptr) oop->print(); tty->print_cr(""); tty->flush(); - tty->print("- holder : (%p) ", holder); if (holder != nullptr) holder->print(); tty->print_cr(""); tty->flush(); - tty->print("- array : (%p) ", array); if (array != nullptr) array->print(); tty->print_cr(""); tty->flush(); - tty->print("- off : %d", off); tty->print_cr(""); tty->flush(); - } -#endif bool non_atomic_is_fine = false; if (holder != nullptr) { ciKlass* klass = holder->klass(); ciInstanceKlass* iklass = klass->as_instance_klass(); ciField* field = iklass->get_non_flat_field_by_offset(off); - // instead of field->null_marker_offset(): - // int nm_offset = off + vk->null_marker_offset_in_payload(); ciField* nm_field = iklass->get_field_by_offset(field->null_marker_offset(), false); ciConstant cst = nm_field != nullptr ? holder->field_value(nm_field) : ciConstant() /* invalid */; - if (UseNewCode) { -#ifndef PRODUCT - tty->print("- klass : (%p) ", klass); if (klass != nullptr) klass->print(); tty->print_cr(""); tty->flush(); - tty->print("- field : (%p) ", field); if (field != nullptr) field->print(); tty->print_cr(""); tty->flush(); - tty->print("- nm_field : (%p) ", nm_field); if (nm_field != nullptr) nm_field->print(); tty->print_cr(""); tty->flush(); - tty->print("- cst : "); cst.print(); tty->print_cr(""); tty->flush(); -#endif - } non_atomic_is_fine = FoldStableValues && field->is_stable() && cst.is_valid() && cst.as_boolean(); - } - if (array != nullptr) { + } else if (array != nullptr) { const TypeAryPtr* aryptr = oopptr->is_aryptr(); - //ciFlatArrayKlass* klass = array->klass()->as_flat_array_klass(); - //ciConstant elt = array->element_value_by_offset(off); ciConstant elt = ((ciFlatArray*)array)->null_marker_of_element_by_offset(off); - // ciType* elt_type = array->element_type(); - // array->get_arrayOop(); - if (UseNewCode) { -#ifndef PRODUCT - tty->print("- aryptr : (%p) ", aryptr); if (aryptr != nullptr) aryptr->dump(); tty->print_cr(""); tty->flush(); - // tty->print("- klass : (%p) ", klass); if (klass != nullptr) klass->print(); tty->print_cr(""); tty->flush(); - tty->print("- elt : "); elt.print(); tty->print_cr(""); tty->flush(); - // tty->print("- elt_type : "); elt_type->print(); tty->print_cr(""); tty->flush(); -#endif - } non_atomic_is_fine = FoldStableValues && aryptr->is_stable() && elt.is_valid() && !elt.is_null_or_zero(); } - if (UseNewCode) { - tty->print_cr("[][][][][][][][][][][][][][][][][][][][]"); - } - if (non_atomic_is_fine) { n->as_LoadFlat()->expand_non_atomic(igvn); } else { diff --git a/src/hotspot/share/opto/inlinetypenode.hpp b/src/hotspot/share/opto/inlinetypenode.hpp index cb2b09c0e75..308433e29a1 100644 --- a/src/hotspot/share/opto/inlinetypenode.hpp +++ b/src/hotspot/share/opto/inlinetypenode.hpp @@ -191,7 +191,6 @@ class LoadFlatNode final : public SafePointNode { Node* ptr() const { return in(TypeFunc::Parms + 1); } bool expand_non_atomic(PhaseIterGVN& igvn); void expand_atomic(PhaseIterGVN& igvn); - const ciInlineKlass* vk() const { return _vk; }; private: LoadFlatNode(ciInlineKlass* vk, const TypeTuple* type, bool null_free, DecoratorSet decorators) diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 82530b5eacf..f538801d26f 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -2262,43 +2262,12 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { const TypeInstPtr* tinst = tp->is_instptr(); BasicType bt = value_basic_type(); - if (UseNewCode2) { -#ifndef PRODUCT - tty->print("tinst: "); - tinst->dump(); - tty->print_cr(""); - tty->print_cr("bt: %d", bt); -#endif - } // Optimize loads from constant fields. ciObject* const_oop = tinst->const_oop(); - if (UseNewCode2) { -#ifndef PRODUCT - tty->print_cr("const_oop: %p", const_oop); - if (const_oop != nullptr) { - tty->print("const_oop: "); - const_oop->print(); - tty->print_cr(""); - } - tty->print_cr("is_mismatched_access: %d", is_mismatched_access()); -#endif - } if (!is_mismatched_access() && off != Type::OffsetBot && const_oop != nullptr && const_oop->is_instance()) { const Type* con_type = Type::make_constant_from_field(const_oop->as_instance(), off, is_unsigned(), bt); - if (UseNewCode2) { -#ifndef PRODUCT - tty->print_cr("con_type: %p", con_type); -#endif - } if (con_type != nullptr) { - if (UseNewCode2) { -#ifndef PRODUCT - tty->print("con_type: "); - con_type->dump(); - tty->print_cr(""); -#endif - } return con_type; } } diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 5024ce4a952..25bb1cb2238 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -433,17 +433,9 @@ const Type* Type::make_constant_from_field(ciInstance* holder, int off, bool is_ // Instance field field = holder->klass()->as_instance_klass()->get_field_by_offset(off, /*is_static=*/false); } - if (UseNewCode) { - tty->print_cr("field: %p", field); - } if (field == nullptr) { return nullptr; // Wrong offset } - if (UseNewCode) { - tty->print("field: "); - field->print(); - tty->print_cr(""); - } return Type::make_constant_from_field(field, holder, loadbt, is_unsigned_load); } From 63b1d950c244d503e4898d6ce97b10b92bf16710 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Wed, 17 Dec 2025 16:28:39 +0100 Subject: [PATCH 10/12] Cleanup --- src/hotspot/share/ci/ciField.cpp | 2 +- src/hotspot/share/ci/ciInstance.cpp | 3 -- src/hotspot/share/opto/compile.cpp | 43 +++++++++++++++-------------- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp index b8f88d7022e..ac3ac977008 100644 --- a/src/hotspot/share/ci/ciField.cpp +++ b/src/hotspot/share/ci/ciField.cpp @@ -265,7 +265,7 @@ ciField::ciField(ciField* declared_field) { _signature = ciSymbols::bool_signature(); _type = ciType::make(T_BOOLEAN); - _is_constant = (declared_field->is_strict() && declared_field->is_final()) || declared_field->is_constant();; + _is_constant = (declared_field->is_strict() && declared_field->is_final()) || declared_field->is_constant(); _known_to_link_with_put = nullptr; _known_to_link_with_get = nullptr; _constant_value = ciConstant(); diff --git a/src/hotspot/share/ci/ciInstance.cpp b/src/hotspot/share/ci/ciInstance.cpp index 5487ded8dbf..700575e3cf8 100644 --- a/src/hotspot/share/ci/ciInstance.cpp +++ b/src/hotspot/share/ci/ciInstance.cpp @@ -101,9 +101,6 @@ ciConstant ciInstance::field_value_impl(BasicType field_btype, int offset) { return value; } -// ------------------------------------------------------------------ -// ciInstance::null_marker_value -// // Constant value of the null marker. ciConstant ciInstance::null_marker_value() { if (!klass()->is_inlinetype()) { diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index e4f52576524..ced8670e8ad 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2124,32 +2124,33 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { assert(n != nullptr, "unexpected nullptr"); if (n->is_LoadFlat()) { LoadFlatNode* loadn = n->as_LoadFlat(); - - const Type* base_type = igvn.type(loadn->base()); - const TypeOopPtr* oopptr = base_type->isa_oopptr(); - ciObject* oop = oopptr->const_oop(); - ciInstance* holder = oop != nullptr && oop->is_instance() ? oop->as_instance() : nullptr; - ciArray* array = oop != nullptr && oop->is_array() ? oop->as_array() : nullptr; - int off = igvn.type(loadn->ptr())->isa_ptr()->offset(); - bool non_atomic_is_fine = false; - if (holder != nullptr) { - ciKlass* klass = holder->klass(); - ciInstanceKlass* iklass = klass->as_instance_klass(); - ciField* field = iklass->get_non_flat_field_by_offset(off); - ciField* nm_field = iklass->get_field_by_offset(field->null_marker_offset(), false); - ciConstant cst = nm_field != nullptr ? holder->field_value(nm_field) : ciConstant() /* invalid */; - non_atomic_is_fine = FoldStableValues && field->is_stable() && cst.is_valid() && cst.as_boolean(); - } else if (array != nullptr) { - const TypeAryPtr* aryptr = oopptr->is_aryptr(); - ciConstant elt = ((ciFlatArray*)array)->null_marker_of_element_by_offset(off); - non_atomic_is_fine = FoldStableValues && aryptr->is_stable() && elt.is_valid() && !elt.is_null_or_zero(); + if (FoldStableValues) { + const Type* base_type = igvn.type(loadn->base()); + const TypeOopPtr* oopptr = base_type->isa_oopptr(); + ciObject* oop = oopptr->const_oop(); + ciInstance* holder = oop != nullptr && oop->is_instance() ? oop->as_instance() : nullptr; + ciArray* array = oop != nullptr && oop->is_array() ? oop->as_array() : nullptr; + int off = igvn.type(loadn->ptr())->isa_ptr()->offset(); + + if (holder != nullptr) { + ciKlass* klass = holder->klass(); + ciInstanceKlass* iklass = klass->as_instance_klass(); + const ciField* field = iklass->get_non_flat_field_by_offset(off); + ciField* nm_field = iklass->get_field_by_offset(field->null_marker_offset(), false); + ciConstant cst = nm_field != nullptr ? holder->field_value(nm_field) : ciConstant() /* invalid */; + non_atomic_is_fine = FoldStableValues && field->is_stable() && cst.is_valid() && cst.as_boolean(); + } else if (array != nullptr) { + const TypeAryPtr* aryptr = oopptr->is_aryptr(); + ciConstant elt = ((ciFlatArray*)array)->null_marker_of_element_by_offset(off); + non_atomic_is_fine = FoldStableValues && aryptr->is_stable() && elt.is_valid() && !elt.is_null_or_zero(); + } } if (non_atomic_is_fine) { - n->as_LoadFlat()->expand_non_atomic(igvn); + loadn->expand_non_atomic(igvn); } else { - n->as_LoadFlat()->expand_atomic(igvn); + loadn->expand_atomic(igvn); } } else { n->as_StoreFlat()->expand_atomic(igvn); From 9a95f298158abb2c005939d8f61b4885c8136314 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Thu, 18 Dec 2025 10:54:24 +0100 Subject: [PATCH 11/12] Un-problemlist --- test/hotspot/jtreg/ProblemList-enable-preview.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList-enable-preview.txt b/test/hotspot/jtreg/ProblemList-enable-preview.txt index 72a368612ac..05cb7fa7371 100644 --- a/test/hotspot/jtreg/ProblemList-enable-preview.txt +++ b/test/hotspot/jtreg/ProblemList-enable-preview.txt @@ -30,9 +30,6 @@ # Compiler (all Valhalla): compiler/c2/TestVerifyGraphEdges.java 8372723 linux-x64 compiler/c2/irTests/scalarReplacement/ScalarReplacementWithGCBarrierTests.java 8372697 generic-all -compiler/c2/irTests/stable/StableRefArrayTest.java 8372700 generic-all -compiler/c2/irTests/stable/StableRefFinalTest.java 8372700 generic-all -compiler/c2/irTests/stable/StableRefPlainTest.java 8372700 generic-all compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java 8372605 generic-all compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java 8372604 generic-all runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java#id1 8369045 macosx-aarch64 From 80564f4babd56f9e8ae14e48f4e66ba385153e62 Mon Sep 17 00:00:00 2001 From: Marc Chevalier Date: Fri, 19 Dec 2025 13:04:01 +0100 Subject: [PATCH 12/12] review --- src/hotspot/share/ci/ciFlatArray.hpp | 1 - src/hotspot/share/opto/compile.cpp | 19 +++++++++++++------ src/hotspot/share/opto/type.cpp | 2 +- .../c2/irTests/stable/StableRefArrayTest.java | 1 - .../c2/irTests/stable/StableRefPlainTest.java | 2 -- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/ci/ciFlatArray.hpp b/src/hotspot/share/ci/ciFlatArray.hpp index 96b5b4957ec..8cfb3805837 100644 --- a/src/hotspot/share/ci/ciFlatArray.hpp +++ b/src/hotspot/share/ci/ciFlatArray.hpp @@ -56,7 +56,6 @@ class ciFlatArray : public ciArray { ciConstant null_marker_of_element_by_offset_impl(arrayOop ary, int index); ciConstant check_constant_null_marker_cache(int off); void add_to_constant_null_marker_cache(int off, ciConstant val); - //ciConstant element_value_impl(arrayOop ary, int index, int offset); GrowableArray* _constant_null_markers = nullptr; }; diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 84ec140238e..14990b0f349 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2129,11 +2129,18 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { assert(n != nullptr, "unexpected nullptr"); if (n->is_LoadFlat()) { LoadFlatNode* loadn = n->as_LoadFlat(); + // Expending a flat load atomically means that we get a chunk of memory spanning multiple fields + // that we chop with bitwise operations. That is too subtle for some optimizations, especially + // constant folding when fields are constant. But if the flattened field being accessed is read-only + // then no concurrent writes can happen and non-atomic loads are fine, allowing better optimizations. + // A way for fields to be read-only is to be stable and already initialized. Here, we check if the + // field being accessed is stable, and if the null marker of the field/array element is non-zero. + // If so, we know that the stable value was initialized away from the default value (null), and + // that we can assume it's read-only, so can the load can be performed non-atomically. bool non_atomic_is_fine = false; if (FoldStableValues) { - const Type* base_type = igvn.type(loadn->base()); - const TypeOopPtr* oopptr = base_type->isa_oopptr(); - ciObject* oop = oopptr->const_oop(); + const TypeOopPtr* base_type = igvn.type(loadn->base())->isa_oopptr(); + ciObject* oop = base_type->const_oop(); ciInstance* holder = oop != nullptr && oop->is_instance() ? oop->as_instance() : nullptr; ciArray* array = oop != nullptr && oop->is_array() ? oop->as_array() : nullptr; int off = igvn.type(loadn->ptr())->isa_ptr()->offset(); @@ -2144,11 +2151,11 @@ void Compile::process_flat_accesses(PhaseIterGVN& igvn) { const ciField* field = iklass->get_non_flat_field_by_offset(off); ciField* nm_field = iklass->get_field_by_offset(field->null_marker_offset(), false); ciConstant cst = nm_field != nullptr ? holder->field_value(nm_field) : ciConstant() /* invalid */; - non_atomic_is_fine = FoldStableValues && field->is_stable() && cst.is_valid() && cst.as_boolean(); + non_atomic_is_fine = field->is_stable() && cst.is_valid() && cst.as_boolean(); } else if (array != nullptr) { - const TypeAryPtr* aryptr = oopptr->is_aryptr(); + const TypeAryPtr* aryptr = base_type->is_aryptr(); ciConstant elt = ((ciFlatArray*)array)->null_marker_of_element_by_offset(off); - non_atomic_is_fine = FoldStableValues && aryptr->is_stable() && elt.is_valid() && !elt.is_null_or_zero(); + non_atomic_is_fine = aryptr->is_stable() && elt.is_valid() && !elt.is_null_or_zero(); } } diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 0c653a76d75..2ad41ae8994 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -392,7 +392,7 @@ static const Type* make_constant_from_non_flat_array_element(ciArray* array, int !con.is_null_or_zero()) { // not a default value bool is_narrow_oop = (loadbt == T_NARROWOOP); return Type::make_from_constant(con, /*require_constant=*/true, stable_dimension, is_narrow_oop, /*is_autobox_cache=*/false); - } + } return nullptr; } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java index 11199c3c515..b0fd75e3fa3 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java @@ -116,7 +116,6 @@ static int testNoFold() { @IR(applyIf = {"enable-valhalla", "true"}, counts = { IRNode.MEMBAR, "> 0" }) static int testPartialFold() { // Access should not be folded. - // No barriers expected for plain fields. Integer[] is = INIT_EMPTY_CARRIER.field; if (is != null) { Integer i = is[0]; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java index 4c196e24e56..06d0fc1f7d5 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java @@ -82,7 +82,6 @@ public void init() { @IR(applyIf = {"enable-valhalla", "true"}, counts = { IRNode.MEMBAR, ">0" }) static int testNoFold() { // Access should not be folded. - // No barriers expected for plain fields. Integer i = BLANK_CARRIER.field; return i != null ? i : 0; } @@ -113,7 +112,6 @@ static Carrier testConstructorFullInit() { @IR(applyIf = {"enable-valhalla", "false"}, failOn = { IRNode.MEMBAR }) @IR(applyIf = {"enable-valhalla", "true"}, counts = { IRNode.MEMBAR, ">0" }) static void testMethodInit() { - // Reference inits do not have membars. INIT_CARRIER.init(); }