Skip to content

Commit c7fa1ca

Browse files
[GR-57743] Backport to 23.1: Eagerly initialize caches in ValueConversions.
PullRequest: graal/18720
2 parents 1202102 + 45f82f5 commit c7fa1ca

File tree

2 files changed

+20
-43
lines changed

2 files changed

+20
-43
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java

Lines changed: 19 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -154,17 +154,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
154154
access.registerReachabilityHandler(MethodHandleFeature::registerInvokersFunctionsForReflection,
155155
ReflectionUtil.lookupMethod(access.findClassByName("java.lang.invoke.Invokers"), "getFunction", byte.class));
156156

157-
access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionBoxFunctionsForReflection,
158-
ReflectionUtil.lookupMethod(ValueConversions.class, "boxExact", Wrapper.class));
159-
160-
access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionUnboxFunctionsForReflection,
161-
ReflectionUtil.lookupMethod(ValueConversions.class, "unbox", Wrapper.class, int.class));
162-
163-
access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionConvertFunctionsForReflection,
164-
ReflectionUtil.lookupMethod(ValueConversions.class, "convertPrimitive", Wrapper.class, Wrapper.class));
165-
166-
access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionIgnoreForReflection,
167-
ReflectionUtil.lookupMethod(ValueConversions.class, "ignore"));
157+
eagerlyInitializeValueConversionsCaches();
168158

169159
access.registerClassInitializerReachabilityHandler(MethodHandleFeature::registerDelegatingMHFunctionsForReflection,
170160
access.findClassByName("java.lang.invoke.DelegatingMethodHandle"));
@@ -263,44 +253,32 @@ private static void registerInvokersFunctionsForReflection(DuringAnalysisAccess
263253
RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "directVarHandleTarget", access.findClassByName("java.lang.invoke.VarHandle")));
264254
}
265255

266-
private static void registerValueConversionBoxFunctionsForReflection(DuringAnalysisAccess access) {
267-
for (Wrapper type : Wrapper.values()) {
268-
if (type.primitiveType().isPrimitive() && type != Wrapper.VOID) {
269-
RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "box" + type.wrapperSimpleName(), type.primitiveType()));
270-
}
271-
}
272-
}
256+
/**
257+
* Eagerly initialize method handle caches in {@link ValueConversions} so that 1) we avoid
258+
* reflection registration for conversion methods, and 2) the static analysis already sees a
259+
* consistent snapshot that does not change after analysis when the JDK needs more conversions.
260+
*/
261+
private static void eagerlyInitializeValueConversionsCaches() {
262+
ValueConversions.ignore();
273263

274-
private static void registerValueConversionUnboxFunctionsForReflection(DuringAnalysisAccess access) {
275-
for (Wrapper type : Wrapper.values()) {
276-
if (type.primitiveType().isPrimitive() && type != Wrapper.VOID) {
277-
RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "unbox" + type.wrapperSimpleName(), type.wrapperType()));
278-
RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "unbox" + type.wrapperSimpleName(), Object.class, boolean.class));
264+
for (Wrapper src : Wrapper.values()) {
265+
if (src != Wrapper.VOID && src.primitiveType().isPrimitive()) {
266+
ValueConversions.boxExact(src);
267+
268+
ValueConversions.unboxExact(src, false);
269+
ValueConversions.unboxExact(src, true);
270+
ValueConversions.unboxWiden(src);
271+
ValueConversions.unboxCast(src);
279272
}
280-
}
281-
}
282273

283-
private static void registerValueConversionConvertFunctionsForReflection(DuringAnalysisAccess access) {
284-
for (Wrapper src : Wrapper.values()) {
285-
for (Wrapper dest : Wrapper.values()) {
286-
if (src != dest && src.primitiveType().isPrimitive() && src != Wrapper.VOID && dest.primitiveType().isPrimitive() && dest != Wrapper.VOID) {
287-
RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, valueConverterName(src, dest), src.primitiveType()));
274+
for (Wrapper dst : Wrapper.values()) {
275+
if (src != Wrapper.VOID && dst != Wrapper.VOID && (src == dst || (src.primitiveType().isPrimitive() && dst.primitiveType().isPrimitive()))) {
276+
ValueConversions.convertPrimitive(src, dst);
288277
}
289278
}
290279
}
291280
}
292281

293-
private static String valueConverterName(Wrapper src, Wrapper dest) {
294-
String srcType = src.primitiveSimpleName();
295-
String destType = dest.primitiveSimpleName();
296-
/* Capitalize first letter of destination type */
297-
return srcType + "To" + destType.substring(0, 1).toUpperCase() + destType.substring(1);
298-
}
299-
300-
private static void registerValueConversionIgnoreForReflection(DuringAnalysisAccess access) {
301-
RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "ignore", Object.class));
302-
}
303-
304282
private static void registerDelegatingMHFunctionsForReflection(DuringAnalysisAccess access) {
305283
Class<?> delegatingMHClazz = access.findClassByName("java.lang.invoke.DelegatingMethodHandle");
306284
RuntimeReflection.register(ReflectionUtil.lookupMethod(delegatingMHClazz, "getTarget"));

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979
import com.oracle.svm.core.hub.ClassForNameSupport;
8080
import com.oracle.svm.core.hub.DynamicHub;
8181
import com.oracle.svm.core.reflect.SubstrateAccessor;
82-
import com.oracle.svm.core.util.UserError;
8382
import com.oracle.svm.core.util.VMError;
8483
import com.oracle.svm.hosted.ConditionalConfigurationRegistry;
8584
import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl;
@@ -482,7 +481,7 @@ public void registerFieldLookup(ConfigurationCondition condition, Class<?> decla
482481

483482
private void checkNotSealed() {
484483
if (sealed) {
485-
throw UserError.abort("Too late to add classes, methods, and fields for reflective access. Registration must happen in a Feature before the analysis has finished.");
484+
throw new UnsupportedFeatureException("Too late to add classes, methods, and fields for reflective access. Registration must happen in a Feature before the analysis has finished.");
486485
}
487486
}
488487

0 commit comments

Comments
 (0)