Skip to content

Commit 2630a23

Browse files
committed
[GR-62459] Make AnnotationParser layer aware
PullRequest: graal/20188
2 parents 1044aca + 7f00610 commit 2630a23

File tree

5 files changed

+127
-29
lines changed

5 files changed

+127
-29
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.core.hub;
26+
27+
import java.util.EnumSet;
28+
29+
import org.graalvm.nativeimage.ImageSingletons;
30+
31+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
32+
import com.oracle.svm.core.feature.InternalFeature;
33+
import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo;
34+
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
35+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
36+
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
37+
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
38+
import com.oracle.svm.core.reflect.target.Target_jdk_internal_reflect_ConstantPool;
39+
40+
/**
41+
* This singleton provides the {@link Target_jdk_internal_reflect_ConstantPool} for the requested
42+
* layer. Native Image normally does not use the constant pool, but in the context of Layered Image,
43+
* the constant pool needs to be associated with a layer number. More information can be found in
44+
* {@link Target_jdk_internal_reflect_ConstantPool}.
45+
*/
46+
public class ConstantPoolProvider implements MultiLayeredImageSingleton, UnsavedSingleton {
47+
private final Target_jdk_internal_reflect_ConstantPool constantPool = new Target_jdk_internal_reflect_ConstantPool(DynamicImageLayerInfo.singleton().layerNumber);
48+
49+
public static ConstantPoolProvider[] singletons() {
50+
return MultiLayeredImageSingleton.getAllLayers(ConstantPoolProvider.class);
51+
}
52+
53+
public Target_jdk_internal_reflect_ConstantPool getConstantPool() {
54+
return constantPool;
55+
}
56+
57+
@Override
58+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
59+
return LayeredImageSingletonBuilderFlags.RUNTIME_ACCESS_ONLY;
60+
}
61+
}
62+
63+
@AutomaticallyRegisteredFeature
64+
class ConstantPoolProviderFeature implements InternalFeature {
65+
@Override
66+
public boolean isInConfiguration(IsInConfigurationAccess access) {
67+
return ImageLayerBuildingSupport.buildingImageLayer();
68+
}
69+
70+
@Override
71+
public void beforeAnalysis(BeforeAnalysisAccess access) {
72+
/*
73+
* The ConstantPoolProvider needs to be created after the afterRegistration hook as it
74+
* depends on the DynamicImageLayerInfo.
75+
*/
76+
ImageSingletons.add(ConstantPoolProvider.class, new ConstantPoolProvider());
77+
}
78+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
import com.oracle.svm.core.heap.UnknownObjectField;
112112
import com.oracle.svm.core.heap.UnknownPrimitiveField;
113113
import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo;
114+
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
114115
import com.oracle.svm.core.jdk.JDK21OrEarlier;
115116
import com.oracle.svm.core.jdk.JDKLatest;
116117
import com.oracle.svm.core.jdk.ProtectionDomainSupport;
@@ -1911,7 +1912,11 @@ byte[] getRawTypeAnnotations() {
19111912

19121913
@Substitute
19131914
Target_jdk_internal_reflect_ConstantPool getConstantPool() {
1914-
return null;
1915+
if (ImageLayerBuildingSupport.buildingImageLayer()) {
1916+
return ConstantPoolProvider.singletons()[layerId].getConstantPool();
1917+
} else {
1918+
return null;
1919+
}
19151920
}
19161921

19171922
@Substitute

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/RuntimeMetadataDecoder.java

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
import org.graalvm.nativeimage.Platforms;
3737

3838
import com.oracle.svm.core.hub.DynamicHub;
39+
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
40+
import com.oracle.svm.core.reflect.target.Target_jdk_internal_reflect_ConstantPool;
3941

4042
import jdk.graal.compiler.api.replacements.Fold;
4143

@@ -158,22 +160,6 @@ static MetadataAccessor singleton() {
158160
return ImageSingletons.lookup(MetadataAccessor.class);
159161
}
160162

161-
default <T> T getObject(int index) {
162-
return getObject(index, 0);
163-
}
164-
165-
default Class<?> getClass(int index) {
166-
return getClass(index, 0);
167-
}
168-
169-
default String getMemberName(int index) {
170-
return getMemberName(index, 0);
171-
}
172-
173-
default String getOtherString(int index) {
174-
return getOtherString(index, 0);
175-
}
176-
177163
<T> T getObject(int index, int layerId);
178164

179165
Class<?> getClass(int index, int layerId);
@@ -182,4 +168,12 @@ default String getOtherString(int index) {
182168

183169
String getOtherString(int index, int layerId);
184170
}
171+
172+
static int getConstantPoolLayerId(Target_jdk_internal_reflect_ConstantPool constPool) {
173+
if (ImageLayerBuildingSupport.buildingImageLayer()) {
174+
return constPool.getLayerId();
175+
} else {
176+
return 0;
177+
}
178+
}
185179
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_jdk_internal_reflect_ConstantPool.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,27 @@
3030
/**
3131
* All usages of ConstantPool are substituted to go through
3232
* {@link com.oracle.svm.core.reflect.RuntimeMetadataDecoder.MetadataAccessor}.
33+
* <p>
34+
* In Native Image, the constant pool is not used. However, in the context of Layered Image, the
35+
* constant pool needs to be able to provide the layer number it is associated with. This is because
36+
* the {@link com.oracle.svm.core.reflect.RuntimeMetadataDecoder.MetadataAccessor} needs a layer
37+
* number for retrieving the information in the correct layer and in some cases, only the constant
38+
* pool can provide this information. The constant pool is only used with Layered Image, and only to
39+
* provide a layer number.
3340
*/
3441
@TargetClass(className = "jdk.internal.reflect.ConstantPool")
3542
@Substitute
3643
public final class Target_jdk_internal_reflect_ConstantPool {
44+
/**
45+
* The layer number associated with this constant pool.
46+
*/
47+
private final int layerId;
48+
49+
public Target_jdk_internal_reflect_ConstantPool(int layerId) {
50+
this.layerId = layerId;
51+
}
52+
53+
public int getLayerId() {
54+
return layerId;
55+
}
3756
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_sun_reflect_annotation_AnnotationParser.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
package com.oracle.svm.core.reflect.target;
2626

27+
import static com.oracle.svm.core.reflect.RuntimeMetadataDecoder.getConstantPoolLayerId;
28+
2729
import java.lang.annotation.Annotation;
2830
import java.lang.annotation.AnnotationFormatError;
2931
import java.lang.reflect.Method;
@@ -64,7 +66,7 @@ private static Annotation parseAnnotation2(ByteBuffer buf,
6466
}
6567
Class<? extends Annotation> annotationClass;
6668
try {
67-
annotationClass = (Class<? extends Annotation>) MetadataAccessor.singleton().getClass(typeIndex);
69+
annotationClass = (Class<? extends Annotation>) MetadataAccessor.singleton().getClass(typeIndex, getConstantPoolLayerId(constPool));
6870
} catch (Throwable e) {
6971
if (exceptionOnMissingAnnotationClass) {
7072
throw new TypeNotPresentException("[unknown]", e);
@@ -91,7 +93,7 @@ private static Annotation parseAnnotation2(ByteBuffer buf,
9193
int numMembers = buf.getShort() & 0xFFFF;
9294
for (int i = 0; i < numMembers; i++) {
9395
int memberNameIndex = buf.getInt();
94-
String memberName = MetadataAccessor.singleton().getMemberName(memberNameIndex);
96+
String memberName = MetadataAccessor.singleton().getMemberName(memberNameIndex, getConstantPoolLayerId(constPool));
9597
Class<?> memberType = memberTypes.get(memberName);
9698

9799
if (memberType == null) {
@@ -116,11 +118,11 @@ public static native Object parseMemberValue(Class<?> memberType,
116118

117119
@Substitute
118120
private static Object parseClassValue(ByteBuffer buf,
119-
@SuppressWarnings("unused") Target_jdk_internal_reflect_ConstantPool constPool,
121+
Target_jdk_internal_reflect_ConstantPool constPool,
120122
@SuppressWarnings("unused") Class<?> container) {
121123
int classIndex = buf.getInt();
122124
try {
123-
return MetadataAccessor.singleton().getClass(classIndex);
125+
return MetadataAccessor.singleton().getClass(classIndex, getConstantPoolLayerId(constPool));
124126
} catch (Throwable t) {
125127
throw VMError.shouldNotReachHereSubstitution(); // ExcludeFromJacocoGeneratedReport
126128
}
@@ -129,13 +131,13 @@ private static Object parseClassValue(ByteBuffer buf,
129131
@Substitute
130132
@SuppressWarnings({"unchecked", "rawtypes"})
131133
private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer buf,
132-
@SuppressWarnings("unused") Target_jdk_internal_reflect_ConstantPool constPool,
134+
Target_jdk_internal_reflect_ConstantPool constPool,
133135
@SuppressWarnings("unused") Class<?> container) {
134136
int typeIndex = buf.getInt();
135137
int constNameIndex = buf.getInt();
136-
String constName = MetadataAccessor.singleton().getMemberName(constNameIndex);
138+
String constName = MetadataAccessor.singleton().getMemberName(constNameIndex, getConstantPoolLayerId(constPool));
137139

138-
if (!enumType.isEnum() || enumType != MetadataAccessor.singleton().getClass(typeIndex)) {
140+
if (!enumType.isEnum() || enumType != MetadataAccessor.singleton().getClass(typeIndex, getConstantPoolLayerId(constPool))) {
139141
Target_sun_reflect_annotation_AnnotationTypeMismatchExceptionProxy e = new Target_sun_reflect_annotation_AnnotationTypeMismatchExceptionProxy();
140142
e.constructor(enumType.getTypeName() + "." + constName);
141143
return e;
@@ -150,7 +152,7 @@ private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer
150152

151153
@Substitute
152154
private static Object parseConst(int tag,
153-
ByteBuffer buf, @SuppressWarnings("unused") Target_jdk_internal_reflect_ConstantPool constPool) {
155+
ByteBuffer buf, Target_jdk_internal_reflect_ConstantPool constPool) {
154156
switch (tag) {
155157
case 'B':
156158
return buf.get();
@@ -171,9 +173,9 @@ private static Object parseConst(int tag,
171173
assert value == 1 || value == 0;
172174
return value == 1;
173175
case 's':
174-
return MetadataAccessor.singleton().getOtherString(buf.getInt());
176+
return MetadataAccessor.singleton().getOtherString(buf.getInt(), getConstantPoolLayerId(constPool));
175177
case 'E':
176-
return MetadataAccessor.singleton().getObject(buf.getInt());
178+
return MetadataAccessor.singleton().getObject(buf.getInt(), getConstantPoolLayerId(constPool));
177179
default:
178180
throw new AnnotationFormatError(
179181
"Invalid member-value tag in annotation: " + tag);
@@ -339,7 +341,7 @@ private static Object parseBooleanArray(int length,
339341

340342
@Substitute
341343
private static Object parseStringArray(int length,
342-
ByteBuffer buf, @SuppressWarnings("unused") Target_jdk_internal_reflect_ConstantPool constPool) {
344+
ByteBuffer buf, Target_jdk_internal_reflect_ConstantPool constPool) {
343345
String[] result = new String[length];
344346
boolean typeMismatch = false;
345347
int tag = 0;
@@ -348,7 +350,7 @@ private static Object parseStringArray(int length,
348350
tag = buf.get();
349351
if (tag == 's') {
350352
int index = buf.getInt();
351-
result[i] = MetadataAccessor.singleton().getOtherString(index);
353+
result[i] = MetadataAccessor.singleton().getOtherString(index, getConstantPoolLayerId(constPool));
352354
} else {
353355
skipMemberValue(tag, buf);
354356
typeMismatch = true;

0 commit comments

Comments
 (0)