diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index 736ed4e676d1e..f4b36674968f5 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -947,7 +947,7 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { Node* ex_klass_node = nullptr; if (has_exception_handler() && !ex_type->klass_is_exact()) { Node* p = basic_plus_adr( ex_node, ex_node, oopDesc::klass_offset_in_bytes()); - ex_klass_node = _gvn.transform(LoadKlassNode::make(_gvn, nullptr, immutable_memory(), p, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT)); + ex_klass_node = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT)); // Compute the exception klass a little more cleverly. // Obvious solution is to simple do a LoadKlass from the 'ex_node'. @@ -965,7 +965,7 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { continue; } Node* p = basic_plus_adr(ex_in, ex_in, oopDesc::klass_offset_in_bytes()); - Node* k = _gvn.transform( LoadKlassNode::make(_gvn, nullptr, immutable_memory(), p, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT)); + Node* k = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeInstKlassPtr::OBJECT)); ex_klass_node->init_req( i, k ); } ex_klass_node = _gvn.transform(ex_klass_node); diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 82a7eaaea8218..2af70960f5469 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -1200,7 +1200,7 @@ Node* GraphKit::load_object_klass(Node* obj) { Node* akls = AllocateNode::Ideal_klass(obj, &_gvn); if (akls != nullptr) return akls; Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); - return _gvn.transform(LoadKlassNode::make(_gvn, nullptr, immutable_memory(), k_adr, TypeInstPtr::KLASS)); + return _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), k_adr, TypeInstPtr::KLASS)); } //-------------------------load_array_length----------------------------------- @@ -2779,7 +2779,7 @@ Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, No if (might_be_cache && mem != nullptr) { kmem = mem->is_MergeMem() ? mem->as_MergeMem()->memory_at(C->get_alias_index(gvn.type(p2)->is_ptr())) : mem; } - Node *nkls = gvn.transform(LoadKlassNode::make(gvn, nullptr, kmem, p2, gvn.type(p2)->is_ptr(), TypeInstKlassPtr::OBJECT_OR_NULL)); + Node* nkls = gvn.transform(LoadKlassNode::make(gvn, kmem, p2, gvn.type(p2)->is_ptr(), TypeInstKlassPtr::OBJECT_OR_NULL)); // Compile speed common case: ARE a subtype and we canNOT fail if (superklass == nkls) { diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 7ef030ccd7d4d..81b8bbe34da85 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -3006,7 +3006,7 @@ bool LibraryCallKit::inline_native_classID() { IdealKit ideal(this); #define __ ideal. IdealVariable result(ideal); __ declarations_done(); - Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, nullptr, immutable_memory(), + Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), basic_plus_adr(cls, java_lang_Class::klass_offset()), TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT_OR_NULL)); @@ -3036,7 +3036,7 @@ bool LibraryCallKit::inline_native_classID() { ideal.set(result, _gvn.transform(new URShiftLNode(kls_trace_id_raw, ideal.ConI(TRACE_ID_SHIFT)))); } __ else_(); { - Node* array_kls = _gvn.transform(LoadKlassNode::make(_gvn, nullptr, immutable_memory(), + Node* array_kls = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), basic_plus_adr(cls, java_lang_Class::array_klass_offset()), TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT_OR_NULL)); __ if_then(array_kls, BoolTest::ne, null()); { @@ -3830,7 +3830,7 @@ Node* LibraryCallKit::load_klass_from_mirror_common(Node* mirror, if (region == nullptr) never_see_null = true; Node* p = basic_plus_adr(mirror, offset); const TypeKlassPtr* kls_type = TypeInstKlassPtr::OBJECT_OR_NULL; - Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, nullptr, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type)); + Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type)); Node* null_ctl = top(); kls = null_check_oop(kls, &null_ctl, never_see_null); if (region != nullptr) { @@ -4026,7 +4026,7 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) { phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror()))); // If we fall through, it's a plain class. Get its _super. p = basic_plus_adr(kls, in_bytes(Klass::super_offset())); - kls = _gvn.transform(LoadKlassNode::make(_gvn, nullptr, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT_OR_NULL)); + kls = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT_OR_NULL)); null_ctl = top(); kls = null_check_oop(kls, &null_ctl); if (null_ctl != top()) { @@ -4180,7 +4180,7 @@ bool LibraryCallKit::inline_native_subtype_check() { args[which_arg] = arg; Node* p = basic_plus_adr(arg, class_klass_offset); - Node* kls = LoadKlassNode::make(_gvn, nullptr, immutable_memory(), p, adr_type, kls_type); + Node* kls = LoadKlassNode::make(_gvn, immutable_memory(), p, adr_type, kls_type); klasses[which_arg] = _gvn.transform(kls); } diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 855506faa95e2..1bd35f9dcc980 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2338,7 +2338,7 @@ void PhaseMacroExpand::expand_subtypecheck_node(SubTypeCheckNode *check) { subklass = obj_or_subklass; } else { Node* k_adr = basic_plus_adr(obj_or_subklass, oopDesc::klass_offset_in_bytes()); - subklass = _igvn.transform(LoadKlassNode::make(_igvn, nullptr, C->immutable_memory(), k_adr, TypeInstPtr::KLASS)); + subklass = _igvn.transform(LoadKlassNode::make(_igvn, C->immutable_memory(), k_adr, TypeInstPtr::KLASS)); } Node* not_subtype_ctrl = Phase::gen_subtype_check(subklass, superklass, &ctrl, nullptr, _igvn, check->method(), check->bci()); diff --git a/src/hotspot/share/opto/macroArrayCopy.cpp b/src/hotspot/share/opto/macroArrayCopy.cpp index ab81507322cb7..e37c961e88d66 100644 --- a/src/hotspot/share/opto/macroArrayCopy.cpp +++ b/src/hotspot/share/opto/macroArrayCopy.cpp @@ -642,7 +642,7 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode* // (At this point we can assume disjoint_bases, since types differ.) int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node* p1 = basic_plus_adr(dest_klass, ek_offset); - Node* n1 = LoadKlassNode::make(_igvn, nullptr, C->immutable_memory(), p1, TypeRawPtr::BOTTOM); + Node* n1 = LoadKlassNode::make(_igvn, C->immutable_memory(), p1, TypeRawPtr::BOTTOM); Node* dest_elem_klass = transform_later(n1); Node* cv = generate_checkcast_arraycopy(&local_ctrl, &local_mem, adr_type, diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index a5a746626f8c5..f77ed8be6cbe9 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -2398,19 +2398,19 @@ const Type* LoadSNode::Value(PhaseGVN* phase) const { //============================================================================= //----------------------------LoadKlassNode::make------------------------------ // Polymorphic factory method: -Node* LoadKlassNode::make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk) { +Node* LoadKlassNode::make(PhaseGVN& gvn, Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk) { // sanity check the alias category against the created node type - const TypePtr *adr_type = adr->bottom_type()->isa_ptr(); + const TypePtr* adr_type = adr->bottom_type()->isa_ptr(); assert(adr_type != nullptr, "expecting TypeKlassPtr"); #ifdef _LP64 if (adr_type->is_ptr_to_narrowklass()) { assert(UseCompressedClassPointers, "no compressed klasses"); - Node* load_klass = gvn.transform(new LoadNKlassNode(ctl, mem, adr, at, tk->make_narrowklass(), MemNode::unordered)); + Node* load_klass = gvn.transform(new LoadNKlassNode(mem, adr, at, tk->make_narrowklass(), MemNode::unordered)); return new DecodeNKlassNode(load_klass, load_klass->bottom_type()->make_ptr()); } #endif assert(!adr_type->is_ptr_to_narrowklass() && !adr_type->is_ptr_to_narrowoop(), "should have got back a narrow oop"); - return new LoadKlassNode(ctl, mem, adr, at, tk, MemNode::unordered); + return new LoadKlassNode(mem, adr, at, tk, MemNode::unordered); } //------------------------------Value------------------------------------------ @@ -2418,12 +2418,6 @@ const Type* LoadKlassNode::Value(PhaseGVN* phase) const { return klass_value_common(phase); } -// In most cases, LoadKlassNode does not have the control input set. If the control -// input is set, it must not be removed (by LoadNode::Ideal()). -bool LoadKlassNode::can_remove_control() const { - return false; -} - const Type* LoadNode::klass_value_common(PhaseGVN* phase) const { // Either input is TOP ==> the result is TOP const Type *t1 = phase->type( in(MemNode::Memory) ); diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index ee9db7d1cac1c..b19f7dda98976 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Alibaba Group Holding Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -522,20 +522,18 @@ class LoadNNode : public LoadNode { //------------------------------LoadKlassNode---------------------------------- // Load a Klass from an object class LoadKlassNode : public LoadPNode { -protected: - // In most cases, LoadKlassNode does not have the control input set. If the control - // input is set, it must not be removed (by LoadNode::Ideal()). - virtual bool can_remove_control() const; +private: + LoadKlassNode(Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk, MemOrd mo) + : LoadPNode(nullptr, mem, adr, at, tk, mo) {} + public: - LoadKlassNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk, MemOrd mo) - : LoadPNode(c, mem, adr, at, tk, mo) {} virtual int Opcode() const; virtual const Type* Value(PhaseGVN* phase) const; virtual Node* Identity(PhaseGVN* phase); virtual bool depends_only_on_test() const { return true; } // Polymorphic factory method: - static Node* make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at, + static Node* make(PhaseGVN& gvn, Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk = TypeInstKlassPtr::OBJECT); }; @@ -548,9 +546,12 @@ class LoadKlassNode : public LoadPNode { // extract the actual class pointer. C2's type system is agnostic on whether the // input address directly points into the class pointer. class LoadNKlassNode : public LoadNNode { +private: + friend Node* LoadKlassNode::make(PhaseGVN&, Node*, Node*, const TypePtr*, const TypeKlassPtr*); + LoadNKlassNode(Node* mem, Node* adr, const TypePtr* at, const TypeNarrowKlass* tk, MemOrd mo) + : LoadNNode(nullptr, mem, adr, at, tk, mo) {} + public: - LoadNKlassNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeNarrowKlass *tk, MemOrd mo) - : LoadNNode(c, mem, adr, at, tk, mo) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegN; } virtual int store_Opcode() const { return Op_StoreNKlass; } diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index fd75e2f991c01..f7330d10df3a7 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -2120,7 +2120,7 @@ void Parse::call_register_finalizer() { // finalization. In general this will fold up since the concrete // class is often visible so the access flags are constant. Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() ); - Node* klass = _gvn.transform(LoadKlassNode::make(_gvn, nullptr, immutable_memory(), klass_addr, TypeInstPtr::KLASS)); + Node* klass = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), klass_addr, TypeInstPtr::KLASS)); Node* access_flags_addr = basic_plus_adr(klass, klass, in_bytes(Klass::misc_flags_offset())); Node* access_flags = make_load(nullptr, access_flags_addr, TypeInt::UBYTE, T_BOOLEAN, MemNode::unordered); diff --git a/src/hotspot/share/opto/parseHelper.cpp b/src/hotspot/share/opto/parseHelper.cpp index 17fdb38c6b20e..1a1cea05454f6 100644 --- a/src/hotspot/share/opto/parseHelper.cpp +++ b/src/hotspot/share/opto/parseHelper.cpp @@ -156,7 +156,7 @@ void Parse::array_store_check() { int klass_offset = oopDesc::klass_offset_in_bytes(); Node* p = basic_plus_adr( ary, ary, klass_offset ); // p's type is array-of-OOPS plus klass_offset - Node* array_klass = _gvn.transform(LoadKlassNode::make(_gvn, nullptr, immutable_memory(), p, TypeInstPtr::KLASS)); + Node* array_klass = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS)); // Get the array klass const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr(); @@ -164,11 +164,10 @@ void Parse::array_store_check() { // cast array_klass to EXACT array and uncommon-trap if the cast fails. // Make constant out of the inexact array klass, but use it only if the cast // succeeds. - bool always_see_exact_class = false; - if (MonomorphicArrayCheck - && !too_many_traps(Deoptimization::Reason_array_check) - && !tak->klass_is_exact() - && tak != TypeInstKlassPtr::OBJECT) { + if (MonomorphicArrayCheck && + !too_many_traps(Deoptimization::Reason_array_check) && + !tak->klass_is_exact() && + tak->isa_aryklassptr()) { // Regarding the fourth condition in the if-statement from above: // // If the compiler has determined that the type of array 'ary' (represented @@ -190,16 +189,12 @@ void Parse::array_store_check() { // // See issue JDK-8057622 for details. - always_see_exact_class = true; - // (If no MDO at all, hope for the best, until a trap actually occurs.) - - // Make a constant out of the inexact array klass - const TypeKlassPtr *extak = tak->cast_to_exactness(true); - + // Make a constant out of the exact array klass + const TypeAryKlassPtr* extak = tak->cast_to_exactness(true)->is_aryklassptr(); if (extak->exact_klass(true) != nullptr) { Node* con = makecon(extak); - Node* cmp = _gvn.transform(new CmpPNode( array_klass, con )); - Node* bol = _gvn.transform(new BoolNode( cmp, BoolTest::eq )); + Node* cmp = _gvn.transform(new CmpPNode(array_klass, con)); + Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::eq)); Node* ctrl= control(); { BuildCutout unless(this, bol, PROB_MAX); uncommon_trap(Deoptimization::Reason_array_check, @@ -210,7 +205,7 @@ void Parse::array_store_check() { set_control(ctrl); // Then Don't Do It, just fall into the normal checking } else { // Cast array klass to exactness: // Use the exact constant value we know it is. - replace_in_map(array_klass,con); + replace_in_map(array_klass, con); CompileLog* log = C->log(); if (log != nullptr) { log->elem("cast_up reason='monomorphic_array' from='%d' to='(exact)'", @@ -225,12 +220,9 @@ void Parse::array_store_check() { // Extract the array element class int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset()); - Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset); - // We are allowed to use the constant type only if cast succeeded. If always_see_exact_class is true, - // we must set a control edge from the IfTrue node created by the uncommon_trap above to the - // LoadKlassNode. - Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, always_see_exact_class ? control() : nullptr, - immutable_memory(), p2, tak)); + Node* p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset); + Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p2, tak)); + assert(array_klass->is_Con() == a_e_klass->is_Con() || StressReflectiveCode, "a constant array type must come with a constant element type"); // Check (the hard way) and throw if not a subklass. // Result is ignored, we just need the CFG effects. diff --git a/src/hotspot/share/opto/subtypenode.cpp b/src/hotspot/share/opto/subtypenode.cpp index 9155be40bad98..b58194b87d24b 100644 --- a/src/hotspot/share/opto/subtypenode.cpp +++ b/src/hotspot/share/opto/subtypenode.cpp @@ -195,7 +195,7 @@ bool SubTypeCheckNode::verify(PhaseGVN* phase) { chk_off_X = phase->transform(new ConvI2LNode(chk_off_X)); #endif Node* p2 = phase->transform(new AddPNode(subklass, subklass, chk_off_X)); - Node* nkls = phase->transform(LoadKlassNode::make(*phase, nullptr, C->immutable_memory(), p2, phase->type(p2)->is_ptr(), TypeInstKlassPtr::OBJECT_OR_NULL)); + Node* nkls = phase->transform(LoadKlassNode::make(*phase, C->immutable_memory(), p2, phase->type(p2)->is_ptr(), TypeInstKlassPtr::OBJECT_OR_NULL)); return verify_helper(phase, nkls, cached_t); } @@ -218,7 +218,7 @@ Node* SubTypeCheckNode::load_klass(PhaseGVN* phase) const { Node* subklass = nullptr; if (sub_t->isa_oopptr()) { Node* adr = phase->transform(new AddPNode(obj_or_subklass, obj_or_subklass, phase->MakeConX(oopDesc::klass_offset_in_bytes()))); - subklass = phase->transform(LoadKlassNode::make(*phase, nullptr, phase->C->immutable_memory(), adr, TypeInstPtr::KLASS)); + subklass = phase->transform(LoadKlassNode::make(*phase, phase->C->immutable_memory(), adr, TypeInstPtr::KLASS)); record_for_cleanup(subklass, phase); } else { subklass = obj_or_subklass;