8322726: C2: Unloaded signature class kills argument value
Reviewed-by: kvn, dlong, thartmann
This commit is contained in:
parent
a8e62af733
commit
fa02667d83
@ -1089,13 +1089,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.
|
||||
@ -1103,12 +1104,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
|
||||
|
@ -4271,3 +4271,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;
|
||||
}
|
||||
|
@ -441,6 +441,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 ); }
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user