From ddd28b40d91c364dccb1622d3a12a7131da83d8e Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Tue, 30 Sep 2025 08:49:17 +0200 Subject: [PATCH] [JVMCI] add ResolvedJavaType#isHidden [GR-70158] --- .../HotSpotResolvedObjectTypeImpl.java | 5 +++ .../hotspot/HotSpotResolvedPrimitiveType.java | 5 +++ .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 1 + .../jdk/vm/ci/meta/ResolvedJavaType.java | 9 ++++++ .../ci/runtime/test/TestResolvedJavaType.java | 32 +++++++++++++++++++ 5 files changed, 52 insertions(+) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 67fcf1e027f..c106e6eec13 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -185,6 +185,11 @@ public ResolvedJavaType getComponentType() { return this.equals(componentType) ? null : componentType; } + @Override + public boolean isHidden() { + return (getMiscFlags() & config().jvmAccIsHiddenClass) != 0; + } + @Override public List getPermittedSubclasses() { if (isArray() || isPrimitive()) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java index fac3caf8160..5a411d292e4 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java @@ -102,6 +102,11 @@ public ResolvedJavaType getElementalType() { return this; } + @Override + public boolean isHidden() { + return false; + } + @Override public List getPermittedSubclasses() { return null; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index b83981a6a74..f955adbec2c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -116,6 +116,7 @@ static String getHostArchitectureName() { final int arrayJUShortDataOffset = getFieldOffset("Array::_data", Integer.class); final int arrayJUShortLengthOffset = getFieldOffset("Array::_length", Integer.class, "int"); + final int jvmAccIsHiddenClass = getConstant("KlassFlags::_misc_is_hidden_class", Integer.class); final int jvmAccHasFinalizer = getConstant("KlassFlags::_misc_has_finalizer", Integer.class); final int jvmFieldFlagInternalShift = getConstant("FieldInfo::FieldFlags::_ff_injected", Integer.class); final int jvmFieldFlagStableShift = getConstant("FieldInfo::FieldFlags::_ff_stable", Integer.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index c951d43b3de..73160c9fc63 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -247,6 +247,15 @@ default ResolvedJavaType getElementalType() { @Override ResolvedJavaType getArrayClass(); + /** + * Returns {@code true} if and only if the underlying class is a hidden class. + * + * @return {@code true} if and only if this class is a hidden class + * + * @see Class#isHidden() + */ + boolean isHidden(); + /** * Returns an unmodifiable list of {@link JavaType} objects representing the subclasses or * subinterfaces that are explicitly permitted to extend or implement this sealed class or diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index f67832407b8..caeee6032db 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -61,10 +61,12 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; +import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.AccessibleObject; import java.lang.reflect.AnnotatedElement; @@ -709,6 +711,36 @@ public void getArrayClassTest() { } } + static class HiddenPrototype {} + + @Test + public void isHiddenTest() throws IllegalAccessException { + // non-hidden class + assertFalse(TestResolvedJavaType.class.isHidden()); + assertFalse(metaAccess.lookupJavaType(TestResolvedJavaType.class).isHidden()); + // hidden class + Lookup lookup = MethodHandles.lookup(); + byte[] bytes = getClassBytes(HiddenPrototype.class); + Class c = lookup.defineHiddenClass(bytes, true).lookupClass(); + assertTrue(c.isHidden()); + assertTrue(metaAccess.lookupJavaType(c).isHidden()); + } + + static byte[] getClassBytes(Class originalClass) { + try (InputStream classFile = originalClass.getResourceAsStream("TestResolvedJavaType$HiddenPrototype.class")) { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[16384]; + + while ((nRead = classFile.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + return buffer.toByteArray(); + } catch (IOException e) { + throw new AssertionError(e); + } + } + private static sealed class SealedTestClass permits PermittedTestClass1, PermittedTestClass3 { }