diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandles.java b/src/java.base/share/classes/java/lang/invoke/VarHandles.java index c97d44ba5d3..8c3e123f39a 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java @@ -166,12 +166,15 @@ final class VarHandles { static Field getFieldFromReceiverAndOffset(Class receiverType, long offset, Class fieldType) { - for (Field f : receiverType.getDeclaredFields()) { - if (Modifier.isStatic(f.getModifiers())) continue; + // The receiver may be a referenced class different from the declaring class + for (var declaringClass = receiverType; declaringClass != null; declaringClass = declaringClass.getSuperclass()) { + for (Field f : declaringClass.getDeclaredFields()) { + if (Modifier.isStatic(f.getModifiers())) continue; - if (offset == UNSAFE.objectFieldOffset(f)) { - assert f.getType() == fieldType; - return f; + if (offset == UNSAFE.objectFieldOffset(f)) { + assert f.getType() == fieldType; + return f; + } } } throw new InternalError("Field not found at offset"); diff --git a/test/jdk/java/lang/invoke/VarHandles/describeConstable/DescribeConstableTest.java b/test/jdk/java/lang/invoke/VarHandles/describeConstable/DescribeConstableTest.java index ecda61cac48..0eecbdc3798 100644 --- a/test/jdk/java/lang/invoke/VarHandles/describeConstable/DescribeConstableTest.java +++ b/test/jdk/java/lang/invoke/VarHandles/describeConstable/DescribeConstableTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -21,18 +21,16 @@ * questions. */ -/** +/* * @test - * @bug 8302260 + * @bug 8302260 8372002 * @build p.C p.D p.I p.q.Q * @run junit DescribeConstableTest * @summary Test VarHandle::describeConstable on static fields */ -import java.lang.constant.ClassDesc; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.VarHandle; import java.lang.invoke.VarHandle.VarHandleDesc; import java.util.stream.Stream; @@ -43,7 +41,7 @@ import static org.junit.jupiter.api.Assertions.*; public class DescribeConstableTest { private static final Lookup LOOKUP = MethodHandles.lookup(); - private static Stream testCases() { + private static Stream staticTestCases() { return Stream.of( // static field defined in p.C only Arguments.of(p.C.class, "cString", String.class, p.C.class, "CClass"), @@ -68,8 +66,8 @@ public class DescribeConstableTest { } @ParameterizedTest - @MethodSource("testCases") - void test(Class refc, String name, Class type, Class declaringClass, Object value) throws Throwable { + @MethodSource("staticTestCases") + void testStatic(Class refc, String name, Class type, Class declaringClass, Object value) throws Throwable { var vh = LOOKUP.findStaticVarHandle(refc, name, type); assertEquals(value, vh.get()); @@ -84,6 +82,37 @@ public class DescribeConstableTest { assertEquals(vhd.toString(), varHandleDescString(declaringClass, name, type, true)); } + private static Arguments[] instanceTestCases() { + return new Arguments[] { + // Basic instance field in p.q.Q + Arguments.of(p.q.Q.class, "instanceIntField", int.class, new p.q.Q(), 42), + // p.C.instanceIntField hides the superclass instanceIntField, but it still exists + Arguments.of(p.C.class, "instanceIntField", int.class, new p.C(), 76), + Arguments.of(p.q.Q.class, "instanceIntField", int.class, new p.C(), 42), + // p.D.instanceIntField points to that of p.q.Q + Arguments.of(p.D.class, "instanceIntField", int.class, new p.D(), 42), + }; + } + + @ParameterizedTest + @MethodSource("instanceTestCases") + void testInstance(Class refc, String name, Class type, Object instance, Object value) throws Throwable { + var vh = LOOKUP.findVarHandle(refc, name, type).withInvokeBehavior(); + assertEquals(value, vh.get(instance)); + + var refcDesc = refc.describeConstable().orElseThrow(); + var typeDesc = type.describeConstable().orElseThrow(); + var vhd = vh.describeConstable().orElseThrow(); + var vhd2 = VarHandleDesc.ofField(refcDesc, name, typeDesc); + + assertEquals(value, vhd.resolveConstantDesc(LOOKUP).get(instance)); + assertEquals(value, vhd2.resolveConstantDesc(LOOKUP).get(instance)); + + // The string does not use the declaring class because + // receiver is restricted on the handle + assertEquals(vhd.toString(), varHandleDescString(refc, name, type, false)); + } + static String varHandleDescString(Class declaringClass, String name, Class type, boolean staticField) { return String.format("VarHandleDesc[%s%s.%s:%s]", staticField ? "static " : "", diff --git a/test/jdk/java/lang/invoke/VarHandles/describeConstable/p/C.java b/test/jdk/java/lang/invoke/VarHandles/describeConstable/p/C.java index 353bd26dcf5..5e56451ea25 100644 --- a/test/jdk/java/lang/invoke/VarHandles/describeConstable/p/C.java +++ b/test/jdk/java/lang/invoke/VarHandles/describeConstable/p/C.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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,4 +25,6 @@ package p; public class C extends p.q.Q implements I { public static String cString = "CClass"; + + public int instanceIntField = 76; // Hides the field from Q } diff --git a/test/jdk/java/lang/invoke/VarHandles/describeConstable/p/q/Q.java b/test/jdk/java/lang/invoke/VarHandles/describeConstable/p/q/Q.java index b3bbb8adafc..0461d43b533 100644 --- a/test/jdk/java/lang/invoke/VarHandles/describeConstable/p/q/Q.java +++ b/test/jdk/java/lang/invoke/VarHandles/describeConstable/p/q/Q.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -29,4 +29,6 @@ public class Q { public static String stringField2 = "QClass2"; public static long longField2 = 102L; + + public int instanceIntField = 42; }