From 6d54f99fab0e0b4d4df833a6299ce0c9d5421a98 Mon Sep 17 00:00:00 2001 From: duke Date: Mon, 14 Oct 2024 09:13:00 +0000 Subject: [PATCH] Backport ff2f39f24018436556a8956ec55da433dc697437 --- src/hotspot/share/opto/compile.cpp | 18 ++-- src/hotspot/share/opto/graphKit.cpp | 2 + src/hotspot/share/opto/library_call.cpp | 14 +-- .../types/TestBadMemSliceWithInterfaces.java | 101 ++++++++++++++++++ 4 files changed, 123 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 7cf74ddd055..8ec7cf8fea2 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1483,12 +1483,18 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const { } else { ciInstanceKlass *canonical_holder = ik->get_canonical_holder(offset); assert(offset < canonical_holder->layout_helper_size_in_bytes(), ""); - if (!ik->equals(canonical_holder) || tj->offset() != offset) { - if( is_known_inst ) { - tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, true, nullptr, offset, to->instance_id()); - } else { - tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, nullptr, offset); - } + assert(tj->offset() == offset, "no change to offset expected"); + bool xk = to->klass_is_exact(); + int instance_id = to->instance_id(); + + // If the input type's class is the holder: if exact, the type only includes interfaces implemented by the holder + // but if not exact, it may include extra interfaces: build new type from the holder class to make sure only + // its interfaces are included. + if (xk && ik->equals(canonical_holder)) { + assert(tj == TypeInstPtr::make(to->ptr(), canonical_holder, is_known_inst, nullptr, offset, instance_id), "exact type should be canonical type"); + } else { + assert(xk || !is_known_inst, "Known instance should be exact type"); + tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, is_known_inst, nullptr, offset, instance_id); } } } diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 614a4123c0d..bd4623c7a18 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -1556,6 +1556,7 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, bool mismatched, bool unsafe, uint8_t barrier_data) { + assert(adr_idx == C->get_alias_index(_gvn.type(adr)->isa_ptr()), "slice of address and input slice don't match"); assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" ); const TypePtr* adr_type = nullptr; // debug-mode-only argument debug_only(adr_type = C->get_adr_type(adr_idx)); @@ -1585,6 +1586,7 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt, bool unsafe, int barrier_data) { assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" ); + assert(adr_idx == C->get_alias_index(_gvn.type(adr)->isa_ptr()), "slice of address and input slice don't match"); const TypePtr* adr_type = nullptr; debug_only(adr_type = C->get_adr_type(adr_idx)); Node *mem = memory(adr_idx); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index fead57b0901..8850dcb6766 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -2921,11 +2921,10 @@ bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const ch Node* thread = ideal.thread(); Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_VTMS_transition_offset())); Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_VTMS_transition_offset()); - const TypePtr *addr_type = _gvn.type(addr)->isa_ptr(); sync_kit(ideal); - access_store_at(nullptr, jt_addr, addr_type, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); - access_store_at(nullptr, vt_addr, addr_type, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, jt_addr, _gvn.type(jt_addr)->is_ptr(), hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, vt_addr, _gvn.type(vt_addr)->is_ptr(), hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); ideal.sync_kit(this); } ideal.end_if(); @@ -3283,7 +3282,9 @@ bool LibraryCallKit::inline_native_getEventWriter() { // Load the raw epoch value from the threadObj. Node* threadObj_epoch_offset = basic_plus_adr(threadObj, java_lang_Thread::jfr_epoch_offset()); - Node* threadObj_epoch_raw = access_load_at(threadObj, threadObj_epoch_offset, TypeRawPtr::BOTTOM, TypeInt::CHAR, T_CHAR, + Node* threadObj_epoch_raw = access_load_at(threadObj, threadObj_epoch_offset, + _gvn.type(threadObj_epoch_offset)->isa_ptr(), + TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD); // Mask off the excluded information from the epoch. @@ -3298,7 +3299,8 @@ bool LibraryCallKit::inline_native_getEventWriter() { // Load the raw epoch value from the vthread. Node* vthread_epoch_offset = basic_plus_adr(vthread, java_lang_Thread::jfr_epoch_offset()); - Node* vthread_epoch_raw = access_load_at(vthread, vthread_epoch_offset, TypeRawPtr::BOTTOM, TypeInt::CHAR, T_CHAR, + Node* vthread_epoch_raw = access_load_at(vthread, vthread_epoch_offset, _gvn.type(vthread_epoch_offset)->is_ptr(), + TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD); // Mask off the excluded information from the epoch. @@ -3534,7 +3536,7 @@ void LibraryCallKit::extend_setCurrentThread(Node* jt, Node* thread) { // Load the raw epoch value from the vthread. Node* epoch_offset = basic_plus_adr(thread, java_lang_Thread::jfr_epoch_offset()); - Node* epoch_raw = access_load_at(thread, epoch_offset, TypeRawPtr::BOTTOM, TypeInt::CHAR, T_CHAR, + Node* epoch_raw = access_load_at(thread, epoch_offset, _gvn.type(epoch_offset)->is_ptr(), TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED | C2_CONTROL_DEPENDENT_LOAD); // Mask off the excluded information from the epoch. diff --git a/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java b/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java new file mode 100644 index 00000000000..5090c2dd6cf --- /dev/null +++ b/test/hotspot/jtreg/compiler/types/TestBadMemSliceWithInterfaces.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8340214 + * @summary C2 compilation asserts with "no node with a side effect" in PhaseIdealLoop::try_sink_out_of_loop + * + * @run main/othervm -XX:-BackgroundCompilation TestBadMemSliceWithInterfaces + * + */ + +public class TestBadMemSliceWithInterfaces { + public static void main(String[] args) { + B b = new B(); + C c = new C(); + for (int i = 0; i < 20_000; i++) { + test1(b, c, true); + test1(b, c, false); + b.field = 0; + c.field = 0; + int res = test2(b, c, true); + if (res != 42) { + throw new RuntimeException("incorrect result " + res); + } + res = test2(b, c, false); + if (res != 42) { + throw new RuntimeException("incorrect result " + res); + } + } + } + + private static void test1(B b, C c, boolean flag) { + A a; + if (flag) { + a = b; + } else { + a = c; + } + for (int i = 0; i < 1000; i++) { + a.field = 42; + } + } + + private static int test2(B b, C c, boolean flag) { + A a; + if (flag) { + a = b; + } else { + a = c; + } + int v = 0; + for (int i = 0; i < 2; i++) { + v += a.field; + a.field = 42; + } + return v; + } + + interface I { + void m(); + } + + static class A { + int field; + } + + static class B extends A implements I { + @Override + public void m() { + + } + } + + static class C extends A implements I { + @Override + public void m() { + + } + } +}