From 44e552eb9e3f36289f68639987d8b52a64d3625b Mon Sep 17 00:00:00 2001 From: duke Date: Wed, 5 Jun 2024 14:25:16 +0000 Subject: [PATCH] Backport fa02667d838f08cac7d41dfb4c3e8056ae6165cc --- src/hotspot/share/opto/callGenerator.cpp | 28 ++--- src/hotspot/share/opto/graphKit.cpp | 11 ++ src/hotspot/share/opto/graphKit.hpp | 2 + .../runtime/unloaded/TestMHUnloaded.java | 50 +++++++++ .../unloaded/TestMHUnloadedHelper.java | 103 ++++++++++++++++++ 5 files changed, 181 insertions(+), 13 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloaded.java create mode 100644 test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloadedHelper.java diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 837bbd91013..4025b78ade2 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -1177,13 +1177,14 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* const int receiver_skip = target->is_static() ? 0 : 1; // Cast receiver to its type. if (!target->is_static()) { - Node* arg = kit.argument(0); - const TypeOopPtr* arg_type = arg->bottom_type()->isa_oopptr(); - const Type* sig_type = TypeOopPtr::make_from_klass(signature->accessing_klass()); - if (arg_type != nullptr && !arg_type->higher_equal(sig_type)) { - const Type* recv_type = arg_type->filter_speculative(sig_type); // keep speculative part - Node* cast_obj = gvn.transform(new CheckCastPPNode(kit.control(), arg, recv_type)); - kit.set_argument(0, cast_obj); + Node* recv = kit.argument(0); + Node* casted_recv = kit.maybe_narrow_object_type(recv, signature->accessing_klass()); + if (casted_recv->is_top()) { + print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), + "argument types mismatch"); + return nullptr; // FIXME: effectively dead; issue a halt node instead + } else if (casted_recv != recv) { + kit.set_argument(0, casted_recv); } } // Cast reference arguments to its type. @@ -1191,12 +1192,13 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* ciType* t = signature->type_at(i); if (t->is_klass()) { Node* arg = kit.argument(receiver_skip + j); - const TypeOopPtr* arg_type = arg->bottom_type()->isa_oopptr(); - const Type* sig_type = TypeOopPtr::make_from_klass(t->as_klass()); - if (arg_type != nullptr && !arg_type->higher_equal(sig_type)) { - const Type* narrowed_arg_type = arg_type->filter_speculative(sig_type); // keep speculative part - Node* cast_obj = gvn.transform(new CheckCastPPNode(kit.control(), arg, narrowed_arg_type)); - kit.set_argument(receiver_skip + j, cast_obj); + Node* casted_arg = kit.maybe_narrow_object_type(arg, t->as_klass()); + if (casted_arg->is_top()) { + print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), + "argument types mismatch"); + return nullptr; // FIXME: effectively dead; issue a halt node instead + } else if (casted_arg != arg) { + kit.set_argument(receiver_skip + j, casted_arg); } } j += t->size(); // long and double take two slots diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index c7cfbf0ce93..2d307c27eaf 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -4320,3 +4320,14 @@ Node* GraphKit::make_constant_from_field(ciField* field, Node* obj) { } return nullptr; } + +Node* GraphKit::maybe_narrow_object_type(Node* obj, ciKlass* type) { + const TypeOopPtr* obj_type = obj->bottom_type()->isa_oopptr(); + const TypeOopPtr* sig_type = TypeOopPtr::make_from_klass(type); + if (obj_type != nullptr && sig_type->is_loaded() && !obj_type->higher_equal(sig_type)) { + const Type* narrow_obj_type = obj_type->filter_speculative(sig_type); // keep speculative part + Node* casted_obj = gvn().transform(new CheckCastPPNode(control(), obj, narrow_obj_type)); + return casted_obj; + } + return obj; +} diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index 742e88e0a70..4c0b8bd4b74 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -445,6 +445,8 @@ class GraphKit : public Phase { // Replace all occurrences of one node by another. void replace_in_map(Node* old, Node* neww); + Node* maybe_narrow_object_type(Node* obj, ciKlass* type); + void push(Node* n) { map_not_null(); _map->set_stack(_map->_jvms, _sp++ , n); } Node* pop() { map_not_null(); return _map->stack( _map->_jvms, --_sp ); } Node* peek(int off = 0) { map_not_null(); return _map->stack( _map->_jvms, _sp - off - 1 ); } diff --git a/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloaded.java b/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloaded.java new file mode 100644 index 00000000000..23c6e83a6c5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloaded.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 8322726 + * @library /test/lib + * @modules java.base/jdk.internal.org.objectweb.asm + * + * @compile TestMHUnloaded.java TestMHUnloadedHelper.java + * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.runtime.unloaded.TestMHUnloadedHelper + * @run main/othervm -Xbootclasspath/a:. + * -Xbatch -XX:-TieredCompilation -XX:CompileCommand=exclude,*::test + * -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining + * compiler.runtime.unloaded.TestMHUnloaded + */ + +package compiler.runtime.unloaded; + +import java.lang.invoke.MethodHandles; + +public class TestMHUnloaded { + public static void main(String[] args) { + TestMHUnloadedHelper.test(MethodHandles.lookup()); // launch test in bootstrap loader context + TestMHUnloadedHelper.testConstant(MethodHandles.lookup()); // launch test in bootstrap loader context + System.out.println("TEST PASSED"); + } +} diff --git a/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloadedHelper.java b/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloadedHelper.java new file mode 100644 index 00000000000..176945572e8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloadedHelper.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package compiler.runtime.unloaded; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.function.BiPredicate; +import jdk.internal.org.objectweb.asm.ClassWriter; + +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +// Operates in bootstrap loader context. +public class TestMHUnloadedHelper { + private static final MethodType METHOD_TYPE = MethodType.methodType(BiPredicate.class, + BiPredicate.class, BiPredicate.class); + + static byte[] generateClassFile(Class caller) { + var cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + String name = caller.getName().replace('.', '/'); + cw.visit(V19, ACC_PUBLIC | ACC_SUPER, name, null, "java/lang/Object", null); + { + var mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "test", METHOD_TYPE.toMethodDescriptorString(), null, null); + mv.visitCode(); + mv.visitIntInsn(ALOAD, 1); + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + } + return cw.toByteArray(); + } + + public static MethodHandle generateTest(MethodHandles.Lookup caller) { + // Loaded in the caller context. + byte[] classBytes = generateClassFile(caller.lookupClass()); + try { + MethodHandles.Lookup lookup = caller.defineHiddenClass(classBytes, true); + MethodHandle test = lookup.findStatic(lookup.lookupClass(), "test", METHOD_TYPE); + test = MethodHandles.permuteArguments(test, test.type(), 1, 0); // mix arguments + return test; + } catch (Throwable e) { + throw new AssertionError(e); + } + } + + static BiPredicate[] ps = new BiPredicate[] { (a, b) -> false, + (a, b) -> true }; + + public static void test(MethodHandles.Lookup caller) { + MethodHandle test = generateTest(caller); + + for (int i = 0; i < 20_000; i++) { + try { + BiPredicate pr = (BiPredicate)test.invokeExact(ps[1], ps[0]); + if (pr != ps[1]) { + throw new AssertionError("mismatch"); + } + } catch (Throwable e) { + throw new AssertionError(e); + } + } + } + + public static void testConstant(MethodHandles.Lookup caller) { + MethodHandle test = generateTest(caller); + + // testMH() { return test(ps2, ps1); } where test(a, b) { return b; }. + test = test.bindTo(ps[1]).bindTo(ps[0]); // make argument concrete types visible to the JIT-compiler + + for (int i = 0; i < 20_000; i++) { + try { + BiPredicate pr = (BiPredicate)test.invokeExact(); + if (pr != ps[1]) { + throw new AssertionError("mismatch"); + } + } catch (Throwable e) { + throw new AssertionError(e); + } + } + } +}