diff --git a/src/hotspot/share/c1/c1_Instruction.cpp b/src/hotspot/share/c1/c1_Instruction.cpp index 8c7b199b8a2..cda2b544be4 100644 --- a/src/hotspot/share/c1/c1_Instruction.cpp +++ b/src/hotspot/share/c1/c1_Instruction.cpp @@ -137,14 +137,16 @@ bool Instruction::maybe_flat_array() { if (UseArrayFlattening) { ciType* type = declared_type(); if (type != nullptr) { - if (type->is_obj_array_klass()) { - // Due to array covariance, the runtime type might be a flat array. + if (type->is_ref_array_klass()) { + return false; + } else if (type->is_flat_array_klass()) { + return true; + } else if (type->is_obj_array_klass()) { + // This is the unrefined array type ciKlass* element_klass = type->as_obj_array_klass()->element_klass(); if (element_klass->can_be_inline_klass() && (!element_klass->is_inlinetype() || element_klass->as_inline_klass()->maybe_flat_in_array())) { return true; } - } else if (type->is_flat_array_klass()) { - return true; } else if (type->is_klass() && type->as_klass()->is_java_lang_Object()) { // This can happen as a parameter to System.arraycopy() return true; diff --git a/src/hotspot/share/ci/ciArrayKlass.cpp b/src/hotspot/share/ci/ciArrayKlass.cpp index 7f61f7a85ef..84f24a34d34 100644 --- a/src/hotspot/share/ci/ciArrayKlass.cpp +++ b/src/hotspot/share/ci/ciArrayKlass.cpp @@ -74,14 +74,12 @@ ciType* ciArrayKlass::element_type() { ciType* ciArrayKlass::base_element_type() { if (is_type_array_klass()) { return ciType::make(as_type_array_klass()->element_type()); - } else if (is_obj_array_klass()) { + } else { ciKlass* ek = as_obj_array_klass()->base_element_klass(); if (ek->is_type_array_klass()) { return ciType::make(ek->as_type_array_klass()->element_type()); } return ek; - } else { - return as_flat_array_klass()->base_element_klass(); } } diff --git a/src/hotspot/share/ci/ciClassList.hpp b/src/hotspot/share/ci/ciClassList.hpp index 511e4dfb9b9..e0b78b7586b 100644 --- a/src/hotspot/share/ci/ciClassList.hpp +++ b/src/hotspot/share/ci/ciClassList.hpp @@ -65,8 +65,9 @@ class ciKlass; class ciInstanceKlass; class ciInlineKlass; class ciArrayKlass; -class ciFlatArrayKlass; class ciObjArrayKlass; +class ciFlatArrayKlass; +class ciRefArrayKlass; class ciTypeArrayKlass; // Simulate Java Language style package-private access with diff --git a/src/hotspot/share/ci/ciEnv.hpp b/src/hotspot/share/ci/ciEnv.hpp index c8fd26e2c1d..b427374264a 100644 --- a/src/hotspot/share/ci/ciEnv.hpp +++ b/src/hotspot/share/ci/ciEnv.hpp @@ -199,13 +199,18 @@ class ciEnv : StackObj { if (o == nullptr) return nullptr; return get_object(o)->as_instance(); } + ciObjArrayKlass* get_obj_array_klass(Klass* o) { + if (o == nullptr) return nullptr; + assert(o->is_objArray_klass() && !o->is_flatArray_klass() && !o->is_refArray_klass(), "must be exact"); + return get_metadata(o)->as_obj_array_klass(); + } ciFlatArrayKlass* get_flat_array_klass(Klass* o) { if (o == nullptr) return nullptr; return get_metadata(o)->as_flat_array_klass(); } - ciObjArrayKlass* get_obj_array_klass(Klass* o) { + ciRefArrayKlass* get_ref_array_klass(Klass* o) { if (o == nullptr) return nullptr; - return get_metadata(o)->as_obj_array_klass(); + return get_metadata(o)->as_ref_array_klass(); } ciTypeArrayKlass* get_type_array_klass(Klass* o) { if (o == nullptr) return nullptr; diff --git a/src/hotspot/share/ci/ciFlatArrayKlass.cpp b/src/hotspot/share/ci/ciFlatArrayKlass.cpp deleted file mode 100644 index c6c0b7c75b1..00000000000 --- a/src/hotspot/share/ci/ciFlatArrayKlass.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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/ciFlatArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" -#include "ci/ciInstanceKlass.hpp" -#include "ci/ciObjArrayKlass.hpp" -#include "ci/ciSymbol.hpp" -#include "ci/ciUtilities.hpp" -#include "ci/ciUtilities.inline.hpp" -#include "oops/flatArrayKlass.hpp" -#include "oops/inlineKlass.inline.hpp" - -// ciFlatArrayKlass -// -// This class represents a Klass* in the HotSpot virtual machine -// whose Klass part is a FlatArrayKlass. - -// ------------------------------------------------------------------ -// ciFlatArrayKlass::ciFlatArrayKlass -// -// Constructor for loaded inline type array klasses. -ciFlatArrayKlass::ciFlatArrayKlass(Klass* h_k) : ciArrayKlass(h_k) { - assert(get_Klass()->is_flatArray_klass(), "wrong type"); - InlineKlass* element_Klass = get_FlatArrayKlass()->element_klass(); - _base_element_klass = CURRENT_ENV->get_klass(element_Klass); - assert(_base_element_klass->is_inlinetype(), "bad base klass"); - if (dimension() == 1) { - _element_klass = _base_element_klass; - } else { - _element_klass = nullptr; - } - if (!ciObjectFactory::is_initialized()) { - assert(_element_klass->is_java_lang_Object(), "only arrays of object are shared"); - } -} - -// ------------------------------------------------------------------ -// ciFlatArrayKlass::element_klass -// -// What is the one-level element type of this array? -ciKlass* ciFlatArrayKlass::element_klass() { - if (_element_klass == nullptr) { - assert(dimension() > 1, "_element_klass should not be nullptr"); - assert(is_loaded(), "FlatArrayKlass must be loaded"); - // Produce the element klass. - VM_ENTRY_MARK; - Klass* element_Klass = get_FlatArrayKlass()->element_klass(); - _element_klass = CURRENT_THREAD_ENV->get_klass(element_Klass); - } - return _element_klass; -} - -ciKlass* ciFlatArrayKlass::exact_klass() { - assert(element_klass()->is_loaded() && element_klass()->as_inline_klass()->exact_klass() != nullptr, "must have exact klass"); - return this; -} diff --git a/src/hotspot/share/ci/ciFlatArrayKlass.hpp b/src/hotspot/share/ci/ciFlatArrayKlass.hpp index df64fb5457f..f993cba2741 100644 --- a/src/hotspot/share/ci/ciFlatArrayKlass.hpp +++ b/src/hotspot/share/ci/ciFlatArrayKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,56 +25,45 @@ #ifndef SHARE_VM_CI_CIFLATARRAYKLASS_HPP #define SHARE_VM_CI_CIFLATARRAYKLASS_HPP -#include "ci/ciArrayKlass.hpp" +#include "ci/ciInlineKlass.hpp" +#include "ci/ciObjArrayKlass.hpp" #include "oops/flatArrayKlass.hpp" // ciFlatArrayKlass // // This class represents a Klass* in the HotSpot virtual machine // whose Klass part is a FlatArrayKlass. -class ciFlatArrayKlass : public ciArrayKlass { +class ciFlatArrayKlass : public ciObjArrayKlass { CI_PACKAGE_ACCESS friend class ciEnv; -private: - ciKlass* _element_klass; - ciKlass* _base_element_klass; - protected: - ciFlatArrayKlass(Klass* h_k); + ciFlatArrayKlass(Klass* k) : ciObjArrayKlass(k) { + assert(k->is_flatArray_klass(), "wrong type"); + } const FlatArrayKlass* get_FlatArrayKlass() const { return FlatArrayKlass::cast(get_Klass()); } - const char* type_string() { return "ciFlatArrayKlass"; } - - oop loader() { return _base_element_klass->loader(); } - jobject loader_handle() { return _base_element_klass->loader_handle(); } + virtual const char* type_string() override { return "ciFlatArrayKlass"; } public: LayoutKind layout_kind() const { return get_FlatArrayKlass()->layout_kind(); } - // The one-level type of the array elements. - ciKlass* element_klass(); - int log2_element_size() { return Klass::layout_helper_log2_element_size(layout_helper()); } - int element_byte_size() { return 1 << log2_element_size(); } - // The innermost type of the array elements. - ciKlass* base_element_klass() { return _base_element_klass; } + int element_byte_size() { return 1 << log2_element_size(); } // What kind of ciObject is this? - bool is_flat_array_klass() const { return true; } + virtual bool is_flat_array_klass() const override { return true; } - virtual ciKlass* exact_klass(); - - virtual bool can_be_inline_array_klass() { - return true; + virtual ciKlass* exact_klass() override { + assert(element_klass()->as_inline_klass()->exact_klass() != nullptr, "must have exact klass"); + return this; } }; - #endif // SHARE_VM_CI_CIFLATARRAYKLASS_HPP diff --git a/src/hotspot/share/ci/ciMetadata.hpp b/src/hotspot/share/ci/ciMetadata.hpp index de02d780dc8..c0fe6f9a468 100644 --- a/src/hotspot/share/ci/ciMetadata.hpp +++ b/src/hotspot/share/ci/ciMetadata.hpp @@ -57,8 +57,9 @@ class ciMetadata: public ciBaseObject { virtual bool is_instance_klass() const { return false; } virtual bool is_inlinetype() const { return false; } virtual bool is_array_klass() const { return false; } - virtual bool is_flat_array_klass() const { return false; } virtual bool is_obj_array_klass() const { return false; } + virtual bool is_flat_array_klass() const { return false; } + virtual bool is_ref_array_klass() const { return false; } virtual bool is_type_array_klass() const { return false; } virtual bool is_early_larval() const { return false; } virtual bool maybe_flat_in_array() const { return false; } @@ -96,13 +97,17 @@ class ciMetadata: public ciBaseObject { assert(is_array_klass(), "bad cast"); return (ciArrayKlass*)this; } + ciObjArrayKlass* as_obj_array_klass() { + assert(is_obj_array_klass(), "bad cast"); + return (ciObjArrayKlass*)this; + } ciFlatArrayKlass* as_flat_array_klass() { assert(is_flat_array_klass(), "bad cast"); return (ciFlatArrayKlass*)this; } - ciObjArrayKlass* as_obj_array_klass() { - assert(is_obj_array_klass(), "bad cast"); - return (ciObjArrayKlass*)this; + ciRefArrayKlass* as_ref_array_klass() { + assert(is_ref_array_klass(), "bad cast"); + return (ciRefArrayKlass*)this; } ciTypeArrayKlass* as_type_array_klass() { assert(is_type_array_klass(), "bad cast"); diff --git a/src/hotspot/share/ci/ciObjArrayKlass.cpp b/src/hotspot/share/ci/ciObjArrayKlass.cpp index 6b66e4c98e7..c94c986d08b 100644 --- a/src/hotspot/share/ci/ciObjArrayKlass.cpp +++ b/src/hotspot/share/ci/ciObjArrayKlass.cpp @@ -25,9 +25,10 @@ #include "ci/ciFlatArrayKlass.hpp" #include "ci/ciInstanceKlass.hpp" #include "ci/ciObjArrayKlass.hpp" +#include "ci/ciRefArrayKlass.hpp" #include "ci/ciSymbol.hpp" +#include "ci/ciUtilities.hpp" #include "ci/ciUtilities.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "runtime/signature.hpp" @@ -68,7 +69,8 @@ ciObjArrayKlass::ciObjArrayKlass(ciSymbol* array_name, _base_element_klass = base_element_klass; assert(_base_element_klass->is_instance_klass() || _base_element_klass->is_type_array_klass() || - _base_element_klass->is_flat_array_klass(), "bad base klass"); + _base_element_klass->is_flat_array_klass() || + _base_element_klass->is_ref_array_klass(), "bad base klass"); if (dimension == 1) { _element_klass = base_element_klass; } else { @@ -135,7 +137,7 @@ ciSymbol* ciObjArrayKlass::construct_array_name(ciSymbol* element_name, // ciObjArrayKlass::make_impl // // Implementation of make. -ciArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass, bool refined_type, bool null_free, bool atomic) { +ciObjArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass, bool refined_type, bool null_free, bool atomic) { if (element_klass->is_loaded()) { EXCEPTION_CONTEXT; // The element klass is loaded @@ -145,22 +147,24 @@ ciArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass, bool refined_ty CURRENT_THREAD_ENV->record_out_of_memory_failure(); return ciEnv::unloaded_ciobjarrayklass(); } - if (refined_type) { - ArrayKlass::ArrayProperties props = ArrayKlass::ArrayProperties::DEFAULT; - if (null_free) { - assert(element_klass->is_inlinetype(), "Only value class arrays can be null free"); - props = (ArrayKlass::ArrayProperties)(props | ArrayKlass::ArrayProperties::NULL_RESTRICTED); - } - if (!atomic) { - assert(element_klass->is_inlinetype(), "Only value class arrays can be non-atomic"); - props = (ArrayKlass::ArrayProperties)(props | ArrayKlass::ArrayProperties::NON_ATOMIC); - } - array = ObjArrayKlass::cast(array)->klass_with_properties(props, THREAD); + if (!refined_type) { + return CURRENT_THREAD_ENV->get_obj_array_klass(array); + } + + ArrayKlass::ArrayProperties props = ArrayKlass::ArrayProperties::DEFAULT; + if (null_free) { + assert(element_klass->is_inlinetype(), "Only value class arrays can be null free"); + props = (ArrayKlass::ArrayProperties)(props | ArrayKlass::ArrayProperties::NULL_RESTRICTED); } + if (!atomic) { + assert(element_klass->is_inlinetype(), "Only value class arrays can be non-atomic"); + props = (ArrayKlass::ArrayProperties)(props | ArrayKlass::ArrayProperties::NON_ATOMIC); + } + array = ObjArrayKlass::cast(array)->klass_with_properties(props, THREAD); if (array->is_flatArray_klass()) { return CURRENT_THREAD_ENV->get_flat_array_klass(array); } else { - return CURRENT_THREAD_ENV->get_obj_array_klass(array); + return CURRENT_THREAD_ENV->get_ref_array_klass(array); } } @@ -178,7 +182,7 @@ ciArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass, bool refined_ty // ciObjArrayKlass::make // // Make an array klass corresponding to the specified primitive type. -ciArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass, bool refined_type, bool null_free, bool atomic) { +ciObjArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass, bool refined_type, bool null_free, bool atomic) { GUARDED_VM_ENTRY(return make_impl(element_klass, refined_type, null_free, atomic);) } @@ -191,22 +195,6 @@ ciArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass, int dims) { } ciKlass* ciObjArrayKlass::exact_klass() { - if (!is_loaded()) { - return nullptr; - } - ciType* base = base_element_type(); - if (base->is_instance_klass()) { - ciInstanceKlass* ik = base->as_instance_klass(); - // Even though MyValue is final, [LMyValue is only exact if the array - // is null-free due to null-free [LMyValue <: null-able [LMyValue. - if (ik->is_inlinetype() && !is_elem_null_free()) { - return nullptr; - } - if (ik->exact_klass() != nullptr) { - return this; - } - } else if (base->is_primitive_type()) { - return this; - } + // This cannot be an exact klass because the refined types subtype it return nullptr; } diff --git a/src/hotspot/share/ci/ciObjArrayKlass.hpp b/src/hotspot/share/ci/ciObjArrayKlass.hpp index 698d9e443ca..b2f14bd8ed0 100644 --- a/src/hotspot/share/ci/ciObjArrayKlass.hpp +++ b/src/hotspot/share/ci/ciObjArrayKlass.hpp @@ -26,6 +26,7 @@ #define SHARE_CI_CIOBJARRAYKLASS_HPP #include "ci/ciArrayKlass.hpp" +#include "oops/objArrayKlass.hpp" // ciObjArrayKlass // @@ -46,10 +47,10 @@ class ciObjArrayKlass : public ciArrayKlass { int dimension); ObjArrayKlass* get_ObjArrayKlass() { - return (ObjArrayKlass*)get_Klass(); + return ObjArrayKlass::cast(get_Klass()); } - static ciArrayKlass* make_impl(ciKlass* element_klass, bool refined_type = false, bool null_free = false, bool atomic = true); + static ciObjArrayKlass* make_impl(ciKlass* element_klass, bool refined_type = false, bool null_free = false, bool atomic = true); static ciSymbol* construct_array_name(ciSymbol* element_name, int dimension); @@ -68,7 +69,7 @@ class ciObjArrayKlass : public ciArrayKlass { // What kind of ciObject is this? bool is_obj_array_klass() const { return true; } - static ciArrayKlass* make(ciKlass* element_klass, bool refined_type = true, bool null_free = false, bool atomic = true); + static ciObjArrayKlass* make(ciKlass* element_klass, bool refined_type = true, bool null_free = false, bool atomic = true); static ciArrayKlass* make(ciKlass* element_klass, int dims); virtual ciKlass* exact_klass(); diff --git a/src/hotspot/share/ci/ciObjectFactory.cpp b/src/hotspot/share/ci/ciObjectFactory.cpp index 3234125bd6f..0f82e850369 100644 --- a/src/hotspot/share/ci/ciObjectFactory.cpp +++ b/src/hotspot/share/ci/ciObjectFactory.cpp @@ -38,6 +38,7 @@ #include "ci/ciObjArrayKlass.hpp" #include "ci/ciObject.hpp" #include "ci/ciObjectFactory.hpp" +#include "ci/ciRefArrayKlass.hpp" #include "ci/ciReplay.hpp" #include "ci/ciSymbol.hpp" #include "ci/ciSymbols.hpp" @@ -411,10 +412,14 @@ ciMetadata* ciObjectFactory::create_new_metadata(Metadata* o) { } else if (k->is_instance_klass()) { assert(!ReplayCompiles || ciReplay::no_replay_state() || !ciReplay::is_klass_unresolved((InstanceKlass*)k), "must be whitelisted for replay compilation"); return new (arena()) ciInstanceKlass(k); - } else if (k->is_flatArray_klass()) { - return new (arena()) ciFlatArrayKlass(k); - } else if (k->is_refArray_klass() || k->is_objArray_klass()) { - return new (arena()) ciObjArrayKlass(k); + } else if (k->is_objArray_klass()) { + if (k->is_flatArray_klass()) { + return new (arena()) ciFlatArrayKlass(k); + } else if (k->is_refArray_klass()) { + return new (arena()) ciRefArrayKlass(k); + } else { + return new (arena()) ciObjArrayKlass(k); + } } else if (k->is_typeArray_klass()) { return new (arena()) ciTypeArrayKlass(k); } diff --git a/src/hotspot/share/ci/ciRefArrayKlass.hpp b/src/hotspot/share/ci/ciRefArrayKlass.hpp new file mode 100644 index 00000000000..647c841018f --- /dev/null +++ b/src/hotspot/share/ci/ciRefArrayKlass.hpp @@ -0,0 +1,52 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_CI_CIREFARRAYKLASS_HPP +#define SHARE_VM_CI_CIREFARRAYKLASS_HPP + +#include "ci/ciObjArrayKlass.hpp" + +// A ciRefArrayKlass represents the klass of a refined array in which the elements are stored as +// reference +class ciRefArrayKlass : public ciObjArrayKlass { +private: + CI_PACKAGE_ACCESS + friend class ciEnv; + +protected: + ciRefArrayKlass(Klass* k) : ciObjArrayKlass(k) { + assert(k->is_refArray_klass(), "wrong type"); + } + + virtual const char* type_string() override { return "ciRefArrayKlass"; } + +public: + virtual bool is_ref_array_klass() const override { return true; } + + virtual ciKlass* exact_klass() override { + return this; + } +}; + +#endif // SHARE_VM_CI_CIREFARRAYKLASS_HPP diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index f4289bee8b3..dc16c859792 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -319,11 +319,10 @@ ciType* ciTypeFlow::StateVector::type_meet_internal(ciType* t1, ciType* t2, ciTy return object_klass; } else if (k1->is_array_klass() || k2->is_array_klass()) { // When an array meets a non-array, we get Object. - // When (obj/flat)Array meets typeArray, we also get Object. + // When objArray meets typeArray, we also get Object. // And when typeArray meets different typeArray, we again get Object. - // But when (obj/flat)Array meets (obj/flat)Array, we look carefully at element types. - if ((k1->is_obj_array_klass() || k1->is_flat_array_klass()) && - (k2->is_obj_array_klass() || k2->is_flat_array_klass())) { + // But when objArray meets objArray, we look carefully at element types. + if (k1->is_obj_array_klass() && k2->is_obj_array_klass()) { ciType* elem1 = k1->as_array_klass()->element_klass(); ciType* elem2 = k2->as_array_klass()->element_klass(); ciType* elem = elem1; diff --git a/src/hotspot/share/ci/ciTypeFlow.hpp b/src/hotspot/share/ci/ciTypeFlow.hpp index 724913a0ddc..d31399c4681 100644 --- a/src/hotspot/share/ci/ciTypeFlow.hpp +++ b/src/hotspot/share/ci/ciTypeFlow.hpp @@ -340,8 +340,7 @@ class ciTypeFlow : public ArenaObj { ciArrayKlass* pop_objOrFlatArray() { ciType* array = pop_value(); if (array == null_type()) return nullptr; - assert(array->is_obj_array_klass() || array->is_flat_array_klass(), - "must be a flat or an object array type"); + assert(array->is_obj_array_klass(), "must be an object array type"); return array->as_array_klass(); } ciTypeArrayKlass* pop_typeArray() { diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index 9dbe17f7400..105e347b338 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -491,14 +491,8 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) while (ndim-- > 0) { st->print("[]"); } - } else if (cik->is_flat_array_klass()) { - ciKlass* cie = cik->as_flat_array_klass()->base_element_klass(); - cie->print_name_on(st); - st->print("[%d]", spobj->n_fields()); - int ndim = cik->as_array_klass()->dimension() - 1; - while (ndim-- > 0) { - st->print("[]"); - } + } else { + assert(false, "unexpected type %s", cik->name()->as_utf8()); } st->print("={"); uint nf = spobj->n_fields(); diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 156e91a9b09..897c8412873 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -23,9 +23,11 @@ */ #include "asm/register.hpp" +#include "ci/ciArrayKlass.hpp" #include "ci/ciFlatArrayKlass.hpp" #include "ci/ciInlineKlass.hpp" #include "ci/ciObjArray.hpp" +#include "ci/ciObjArrayKlass.hpp" #include "ci/ciUtilities.hpp" #include "classfile/javaClasses.hpp" #include "compiler/compileLog.hpp" @@ -36,6 +38,7 @@ #include "oops/flatArrayKlass.hpp" #include "opto/addnode.hpp" #include "opto/castnode.hpp" +#include "opto/compile.hpp" #include "opto/convertnode.hpp" #include "opto/graphKit.hpp" #include "opto/idealKit.hpp" @@ -53,6 +56,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/bitMap.inline.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" #include "utilities/powerOfTwo.hpp" @@ -1876,30 +1880,36 @@ Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt, return basic_plus_adr(ary, base, scale); } -Node* GraphKit::cast_to_flat_array(Node* array, ciInlineKlass* vk, bool is_null_free, bool is_not_null_free, bool is_atomic) { - assert(vk->maybe_flat_in_array(), "element of type %s cannot be flat in array", vk->name()->as_utf8()); - if (!vk->has_nullable_atomic_layout()) { +Node* GraphKit::cast_to_flat_array(Node* array, ciInlineKlass* elem_vk) { + assert(elem_vk->maybe_flat_in_array(), "no flat array for %s", elem_vk->name()->as_utf8()); + if (!elem_vk->has_atomic_layout() && !elem_vk->has_nullable_atomic_layout()) { + return cast_to_flat_array_exact(array, elem_vk, true, false); + } else if (!elem_vk->has_nullable_atomic_layout() && !elem_vk->has_non_atomic_layout()) { + return cast_to_flat_array_exact(array, elem_vk, true, true); + } else if (!elem_vk->has_atomic_layout() && !elem_vk->has_non_atomic_layout()) { + return cast_to_flat_array_exact(array, elem_vk, false, true); + } + + bool is_null_free = false; + if (!elem_vk->has_nullable_atomic_layout()) { // Element does not have a nullable flat layout, cannot be nullable is_null_free = true; } - if (!vk->has_atomic_layout() && !vk->has_non_atomic_layout()) { - // Element does not have a null-free flat layout, cannot be null-free - is_not_null_free = true; - } - if (is_null_free) { - // TODO 8350865 Impossible type - is_not_null_free = false; - } - bool is_exact = is_null_free || is_not_null_free; - ciArrayKlass* array_klass = ciArrayKlass::make(vk, is_null_free, is_atomic, true); - assert(array_klass->is_elem_null_free() == is_null_free, "inconsistency"); - assert(array_klass->is_elem_atomic() == is_atomic, "inconsistency"); + ciObjArrayKlass* array_klass = ciObjArrayKlass::make(elem_vk, false); + const TypeAryPtr* arytype = TypeOopPtr::make_from_klass(array_klass)->isa_aryptr(); + arytype = arytype->cast_to_flat(true)->cast_to_null_free(is_null_free); + return _gvn.transform(new CastPPNode(control(), array, arytype, ConstraintCastNode::StrongDependency)); +} + +Node* GraphKit::cast_to_flat_array_exact(Node* array, ciInlineKlass* elem_vk, bool is_null_free, bool is_atomic) { + assert(is_null_free || is_atomic, "nullable arrays must be atomic"); + ciObjArrayKlass* array_klass = ciObjArrayKlass::make(elem_vk, true, is_null_free, is_atomic); const TypeAryPtr* arytype = TypeOopPtr::make_from_klass(array_klass)->isa_aryptr(); - arytype = arytype->cast_to_exactness(is_exact); - arytype = arytype->cast_to_not_null_free(is_not_null_free); + assert(arytype->klass_is_exact(), "inconsistency"); + assert(arytype->is_flat(), "inconsistency"); assert(arytype->is_null_free() == is_null_free, "inconsistency"); - assert(arytype->is_not_null_free() == is_not_null_free, "inconsistency"); + assert(arytype->is_not_null_free() == !is_null_free, "inconsistency"); assert(arytype->is_atomic() == is_atomic, "inconsistency"); return _gvn.transform(new CastPPNode(control(), array, arytype, ConstraintCastNode::StrongDependency)); } diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index 9d69401c8be..4daf45f7bbe 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -26,6 +26,8 @@ #define SHARE_OPTO_GRAPHKIT_HPP #include "ci/ciEnv.hpp" +#include "ci/ciInlineKlass.hpp" +#include "ci/ciInstanceKlass.hpp" #include "ci/ciMethodData.hpp" #include "gc/shared/c2/barrierSetC2.hpp" #include "opto/addnode.hpp" @@ -660,7 +662,8 @@ class GraphKit : public Phase { const TypeInt* sizetype = nullptr, // Optional control dependency (for example, on range check) Node* ctrl = nullptr); - Node* cast_to_flat_array(Node* array, ciInlineKlass* elem_vk, bool is_null_free, bool is_not_null_free, bool is_atomic); + Node* cast_to_flat_array(Node* array, ciInlineKlass* elem_vk); + Node* cast_to_flat_array_exact(Node* array, ciInlineKlass* elem_vk, bool is_null_free, bool is_atomic); // Return a load of array element at idx. Node* load_array_element(Node* ary, Node* idx, const TypeAryPtr* arytype, bool set_ctrl); diff --git a/src/hotspot/share/opto/inlinetypenode.cpp b/src/hotspot/share/opto/inlinetypenode.cpp index ae2bfa7f561..e4341631d3e 100644 --- a/src/hotspot/share/opto/inlinetypenode.cpp +++ b/src/hotspot/share/opto/inlinetypenode.cpp @@ -22,6 +22,7 @@ * */ +#include "ci/ciArrayKlass.hpp" #include "ci/ciInlineKlass.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/c2/barrierSetC2.hpp" @@ -554,7 +555,7 @@ void InlineTypeNode::store_flat_array(GraphKit* kit, Node* base, Node* idx) { if (!kit->stopped()) { assert(vk->has_nullable_atomic_layout(), "element type %s does not have a nullable flat layout", vk->name()->as_utf8()); kit->set_all_memory(input_memory_state); - Node* cast = kit->cast_to_flat_array(base, vk, false, true, true); + Node* cast = kit->cast_to_flat_array_exact(base, vk, false, true); Node* ptr = kit->array_element_address(cast, idx, T_FLAT_ELEMENT); store_flat(kit, cast, ptr, true, false, false, decorators); @@ -576,7 +577,7 @@ void InlineTypeNode::store_flat_array(GraphKit* kit, Node* base, Node* idx) { if (!kit->stopped()) { assert(vk->has_atomic_layout(), "element type %s does not have a null-free atomic flat layout", vk->name()->as_utf8()); kit->set_all_memory(input_memory_state); - Node* cast = kit->cast_to_flat_array(base, vk, true, false, true); + Node* cast = kit->cast_to_flat_array_exact(base, vk, true, true); Node* ptr = kit->array_element_address(cast, idx, T_FLAT_ELEMENT); store_flat(kit, cast, ptr, true, false, true, decorators); @@ -590,7 +591,7 @@ void InlineTypeNode::store_flat_array(GraphKit* kit, Node* base, Node* idx) { if (!kit->stopped()) { assert(vk->has_non_atomic_layout(), "element type %s does not have a null-free non-atomic flat layout", vk->name()->as_utf8()); kit->set_all_memory(input_memory_state); - Node* cast = kit->cast_to_flat_array(base, vk, true, false, false); + Node* cast = kit->cast_to_flat_array_exact(base, vk, true, false); Node* ptr = kit->array_element_address(cast, idx, T_FLAT_ELEMENT); store_flat(kit, cast, ptr, false, false, true, decorators); @@ -1081,7 +1082,7 @@ InlineTypeNode* InlineTypeNode::make_from_flat_array(GraphKit* kit, ciInlineKlas if (!kit->stopped()) { assert(vk->has_nullable_atomic_layout(), "element type %s does not have a nullable flat layout", vk->name()->as_utf8()); kit->set_all_memory(input_memory_state); - Node* cast = kit->cast_to_flat_array(base, vk, false, true, true); + Node* cast = kit->cast_to_flat_array_exact(base, vk, false, true); Node* ptr = kit->array_element_address(cast, idx, T_FLAT_ELEMENT); vt_nullable = InlineTypeNode::make_from_flat(kit, vk, cast, ptr, true, false, false, decorators); @@ -1103,7 +1104,7 @@ InlineTypeNode* InlineTypeNode::make_from_flat_array(GraphKit* kit, ciInlineKlas if (!kit->stopped()) { assert(vk->has_atomic_layout(), "element type %s does not have a null-free atomic flat layout", vk->name()->as_utf8()); kit->set_all_memory(input_memory_state); - Node* cast = kit->cast_to_flat_array(base, vk, true, false, true); + Node* cast = kit->cast_to_flat_array_exact(base, vk, true, true); Node* ptr = kit->array_element_address(cast, idx, T_FLAT_ELEMENT); vt_null_free = InlineTypeNode::make_from_flat(kit, vk, cast, ptr, true, false, true, decorators); @@ -1117,7 +1118,7 @@ InlineTypeNode* InlineTypeNode::make_from_flat_array(GraphKit* kit, ciInlineKlas if (!kit->stopped()) { assert(vk->has_non_atomic_layout(), "element type %s does not have a null-free non-atomic flat layout", vk->name()->as_utf8()); kit->set_all_memory(input_memory_state); - Node* cast = kit->cast_to_flat_array(base, vk, true, false, false); + Node* cast = kit->cast_to_flat_array_exact(base, vk, true, false); Node* ptr = kit->array_element_address(cast, idx, T_FLAT_ELEMENT); vt_non_atomic = InlineTypeNode::make_from_flat(kit, vk, cast, ptr, false, false, true, decorators); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index e719beca418..a20fa9c60cf 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -2885,7 +2885,7 @@ bool LibraryCallKit::inline_unsafe_flat_access(bool is_store, AccessKind kind) { // Flat array must have an exact type bool is_null_free = layout != LayoutKind::NULLABLE_ATOMIC_FLAT; bool is_atomic = layout != LayoutKind::NON_ATOMIC_FLAT; - Node* new_base = cast_to_flat_array(base, value_klass, is_null_free, !is_null_free, is_atomic); + Node* new_base = cast_to_flat_array_exact(base, value_klass, is_null_free, is_atomic); replace_in_map(base, new_base); base = new_base; ptr = basic_plus_adr(base, ConvL2X(offset)); diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 20e8d1fbf65..a36af03fa62 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -116,7 +116,7 @@ void Parse::array_load(BasicType bt) { if (!array_type->is_not_flat()) { if (element_ptr->is_inlinetypeptr()) { ciInlineKlass* vk = element_ptr->inline_klass(); - Node* flat_array = cast_to_flat_array(array, vk, false, false, false); + Node* flat_array = cast_to_flat_array(array, vk); Node* vt = InlineTypeNode::make_from_flat_array(this, vk, flat_array, array_index); ideal.set(res, vt); } else { @@ -267,7 +267,7 @@ void Parse::array_store(BasicType bt) { if (vk != nullptr) { // Element type is known, cast and store to flat array layout. - Node* flat_array = cast_to_flat_array(array, vk, false, false, false); + Node* flat_array = cast_to_flat_array(array, vk); // Re-execute flat array store if buffering triggers deoptimization PreserveReexecuteState preexecs(this); diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index fb338c888c4..f67a9d0d1f8 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -26,6 +26,7 @@ #include "ci/ciFlatArrayKlass.hpp" #include "ci/ciInlineKlass.hpp" #include "ci/ciMethodData.hpp" +#include "ci/ciObjArrayKlass.hpp" #include "ci/ciTypeFlow.hpp" #include "classfile/javaClasses.hpp" #include "classfile/symbolTable.hpp" @@ -46,6 +47,7 @@ #include "opto/rangeinference.hpp" #include "opto/runtime.hpp" #include "opto/type.hpp" +#include "runtime/globals.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/checkedCast.hpp" #include "utilities/globalDefinitions.hpp" @@ -3605,9 +3607,7 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* inter assert(this->isa_aryptr(), "only arrays without klass"); _is_ptr_to_narrowoop = UseCompressedOops; } else if (UseCompressedOops && this->isa_aryptr() && this->offset() != arrayOopDesc::length_offset_in_bytes()) { - if (klass()->is_obj_array_klass()) { - _is_ptr_to_narrowoop = true; - } else if (klass()->is_flat_array_klass() && field_offset != Offset::top && field_offset != Offset::bottom) { + if (klass()->is_flat_array_klass() && field_offset != Offset::top && field_offset != Offset::bottom) { // Check if the field of the inline type array element contains oops ciInlineKlass* vk = klass()->as_flat_array_klass()->element_klass()->as_inline_klass(); int foffset = field_offset.get() + vk->payload_offset(); @@ -3620,6 +3620,8 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* inter field_bt = T_BOOLEAN; } _is_ptr_to_narrowoop = UseCompressedOops && ::is_reference_type(field_bt); + } else if (klass()->is_obj_array_klass()) { + _is_ptr_to_narrowoop = UseCompressedOops; } } else if (klass()->is_instance_klass()) { if (this->isa_klassptr()) { @@ -3832,6 +3834,18 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_ } else if (klass->is_obj_array_klass()) { // Element is an object or inline type array. Recursively call ourself. const TypeOopPtr* etype = TypeOopPtr::make_from_klass_common(klass->as_array_klass()->element_klass(), /* klass_change= */ false, try_for_exact, interface_handling); + bool xk = false; + if (klass->is_flat_array_klass() || klass->is_ref_array_klass()) { + // Refined types are exact + xk = true; + } else { + // Try to refine the klass if it only has 1 corresponding refined type + if (etype->klass_is_exact() && !etype->is_inlinetypeptr()) { + klass = ciObjArrayKlass::make(etype->exact_klass()); + xk = true; + } + } + // Determine null-free/flat properties const bool is_null_free = klass->as_array_klass()->is_elem_null_free(); if (is_null_free) { @@ -3843,12 +3857,11 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_ exact_etype = TypeOopPtr::make_from_klass_common(klass->as_array_klass()->element_klass(), /* klass_change= */ true, /* try_for_exact= */ true, interface_handling); } bool not_inline = !exact_etype->can_be_inline_type(); - bool not_null_free = not_inline; - bool not_flat = !UseArrayFlattening || not_inline || (exact_etype->is_inlinetypeptr() && !exact_etype->inline_klass()->maybe_flat_in_array()); + bool not_null_free = not_inline || (xk && !is_null_free); + bool not_flat = !UseArrayFlattening || (xk && !klass->is_flat_array_klass()) || not_inline || + (exact_etype->is_inlinetypeptr() && !exact_etype->inline_klass()->maybe_flat_in_array()); bool atomic = klass->as_array_klass()->is_elem_atomic(); - // Even though MyValue is final, [LMyValue is not exact because null-free [LMyValue is a subtype. - bool xk = etype->klass_is_exact() && !etype->is_inlinetypeptr(); - const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, /* stable= */ false, /* flat= */ false, not_flat, not_null_free, atomic); + const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, /* stable= */ false, /* flat= */ klass->is_flat_array_klass(), not_flat, not_null_free, atomic); // We used to pass NotNull in here, asserting that the sub-arrays // are all not-null. This is not true in generally, as code can // slam nullptrs down in the subarrays. @@ -3863,17 +3876,6 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_ // is not-null. That was not true in general. const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, Offset(0)); return arr; - } else if (klass->is_flat_array_klass()) { - const TypeOopPtr* etype = TypeOopPtr::make_from_klass_raw(klass->as_array_klass()->element_klass(), trust_interfaces); - const bool is_null_free = klass->as_array_klass()->is_elem_null_free(); - if (is_null_free) { - etype = etype->join_speculative(NOTNULL)->is_oopptr(); - } - bool atomic = klass->as_array_klass()->is_elem_atomic(); - const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, /* stable= */ false, /* flat= */ true, /* not_flat= */ false, /* not_null_free= */ false, atomic); - const bool exact = is_null_free; // Only exact if null-free because "null-free [LMyValue <: null-able [LMyValue". - const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, exact, Offset(0)); - return arr; } else { ShouldNotReachHere(); return nullptr; @@ -3904,7 +3906,7 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const etype = etype->join_speculative(TypePtr::NOTNULL)->is_oopptr(); } bool is_atomic = o->as_array()->is_atomic(); - const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()), /* stable= */ false, /* flat= */ false, + const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()), /* stable= */ false, /* flat= */ is_flat, /* not_flat= */ !is_flat, /* not_null_free= */ !is_null_free, /* atomic= */ is_atomic); // We used to pass NotNull in here, asserting that the sub-arrays // are all not-null. This is not true in generally, as code can @@ -3926,23 +3928,6 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const } else { return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, Offset(0)); } - } else if (klass->is_flat_array_klass()) { - const TypeOopPtr* etype = TypeOopPtr::make_from_klass_raw(klass->as_array_klass()->element_klass(), trust_interfaces); - bool is_null_free = o->as_array()->is_null_free(); - if (is_null_free) { - etype = etype->join_speculative(TypePtr::NOTNULL)->is_oopptr(); - } - bool is_atomic = o->as_array()->is_atomic(); - const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()), /* stable= */ false, /* flat= */ true, - /* not_flat= */ false, /* not_null_free= */ !is_null_free, /* atomic= */ is_atomic); - // We used to pass NotNull in here, asserting that the sub-arrays - // are all not-null. This is not true in generally, as code can - // slam nullptrs down in the subarrays. - if (make_constant) { - return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, Offset(0)); - } else { - return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, Offset(0)); - } } fatal("unhandled object type"); @@ -5062,6 +5047,19 @@ const TypeAryPtr* TypeAryPtr::cast_to_size(const TypeInt* new_size) const { return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); } +const TypeAryPtr* TypeAryPtr::cast_to_flat(bool flat) const { + if (flat == is_flat()) { + return this; + } + assert(!flat || !is_not_flat(), "inconsistency"); + const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), flat, is_not_flat(), is_not_null_free(), is_atomic()); + const TypeAryPtr* res = make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); + if (res->speculative() == res->remove_speculative()) { + return res->remove_speculative(); + } + return res; +} + //-------------------------------cast_to_not_flat------------------------------ const TypeAryPtr* TypeAryPtr::cast_to_not_flat(bool not_flat) const { if (not_flat == is_not_flat()) { @@ -5078,6 +5076,27 @@ const TypeAryPtr* TypeAryPtr::cast_to_not_flat(bool not_flat) const { return res; } +const TypeAryPtr* TypeAryPtr::cast_to_null_free(bool null_free) const { + if (null_free == is_null_free()) { + return this; + } + assert(!null_free || !is_not_null_free(), "inconsistency"); + const Type* elem = this->elem(); + const Type* new_elem = elem->make_ptr(); + if (null_free) { + new_elem = new_elem->join_speculative(TypePtr::NOTNULL); + } else { + new_elem = new_elem->meet_speculative(TypePtr::NULL_PTR); + } + new_elem = elem->isa_narrowoop() ? new_elem->make_narrowoop() : new_elem; + const TypeAry* new_ary = TypeAry::make(new_elem, size(), is_stable(), is_flat(), is_not_flat(), is_not_null_free(), is_atomic()); + const TypeAryPtr* res = make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache); + if (res->speculative() == res->remove_speculative()) { + return res->remove_speculative(); + } + return res; +} + //-------------------------------cast_to_not_null_free------------------------- const TypeAryPtr* TypeAryPtr::cast_to_not_null_free(bool not_null_free) const { if (not_null_free == is_not_null_free()) { @@ -6599,7 +6618,11 @@ const TypeAryKlassPtr *TypeAryKlassPtr::make(PTR ptr, const Type* elem, ciKlass* } const TypeAryKlassPtr* TypeAryKlassPtr::make(PTR ptr, ciKlass* k, Offset offset, InterfaceHandling interface_handling, bool not_flat, bool not_null_free, bool flat, bool null_free, bool atomic, bool refined_type) { - if (k->is_obj_array_klass()) { + if (k->is_flat_array_klass()) { + ciKlass* eklass = k->as_flat_array_klass()->element_klass(); + const TypeKlassPtr* etype = TypeKlassPtr::make(eklass, interface_handling)->cast_to_exactness(false); + return TypeAryKlassPtr::make(ptr, etype, k, offset, not_flat, not_null_free, flat, null_free, atomic, refined_type); + } else if (k->is_obj_array_klass()) { // Element is an object array. Recursively call ourself. ciKlass* eklass = k->as_obj_array_klass()->element_klass(); const TypeKlassPtr* etype = TypeKlassPtr::make(eklass, interface_handling)->cast_to_exactness(false); @@ -6608,12 +6631,8 @@ const TypeAryKlassPtr* TypeAryKlassPtr::make(PTR ptr, ciKlass* k, Offset offset, // Element is an typeArray const Type* etype = get_const_basic_type(k->as_type_array_klass()->element_type()); return TypeAryKlassPtr::make(ptr, etype, k, offset, not_flat, not_null_free, flat, null_free, atomic); - } else if (k->is_flat_array_klass()) { - ciKlass* eklass = k->as_flat_array_klass()->element_klass(); - const TypeKlassPtr* etype = TypeKlassPtr::make(eklass, interface_handling)->cast_to_exactness(false); - return TypeAryKlassPtr::make(ptr, etype, k, offset, not_flat, not_null_free, flat, null_free, atomic, refined_type); } else { - ShouldNotReachHere(); + assert(false, "unexpected klass %s", k->name()->as_utf8()); return nullptr; } } @@ -6639,7 +6658,7 @@ const TypeAryKlassPtr* TypeAryKlassPtr::make(ciKlass* klass, InterfaceHandling i // Get the (non-)refined array klass ptr const TypeAryKlassPtr* TypeAryKlassPtr::cast_to_refined_array_klass_ptr(bool refined) const { - if ((refined == is_refined_type()) || !klass_is_exact() || (!exact_klass()->is_obj_array_klass() && !exact_klass()->is_flat_array_klass())) { + if ((refined == is_refined_type()) || !klass_is_exact() || !exact_klass()->is_obj_array_klass()) { return this; } ciKlass* eklass = elem()->is_klassptr()->exact_klass_helper(); @@ -6685,7 +6704,7 @@ ciKlass* TypeAryPtr::compute_klass() const { } // Get element klass - if (is_flat() && el->is_inlinetypeptr()) { + if (klass_is_exact() && is_flat() && el->is_inlinetypeptr()) { // Klass is required by TypeAryPtr::flat_layout_helper() and others if (el->inline_klass() != nullptr) { // TODO 8350865 We assume atomic if the atomic layout is available, use is_atomic() here diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 52b73b8f67c..bf9910994de 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -1773,7 +1773,9 @@ class TypeAryPtr : public TypeOopPtr { virtual const Type *xdual() const; // Compute dual right now. // Inline type array properties + const TypeAryPtr* cast_to_flat(bool flat) const; const TypeAryPtr* cast_to_not_flat(bool not_flat = true) const; + const TypeAryPtr* cast_to_null_free(bool null_free) const; const TypeAryPtr* cast_to_not_null_free(bool not_null_free = true) const; const TypeAryPtr* update_properties(const TypeAryPtr* new_type) const; jint flat_layout_helper() const;