|
33 | 33 | import java.lang.reflect.Member;
|
34 | 34 | import java.lang.reflect.Method;
|
35 | 35 | import java.util.Iterator;
|
36 |
| -import java.util.Locale; |
37 | 36 | import java.util.Optional;
|
38 | 37 | import java.util.concurrent.ConcurrentHashMap;
|
39 | 38 | import java.util.function.Supplier;
|
@@ -163,17 +162,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) {
|
163 | 162 | access.registerReachabilityHandler(MethodHandleFeature::registerInvokersFunctionsForReflection,
|
164 | 163 | ReflectionUtil.lookupMethod(access.findClassByName("java.lang.invoke.Invokers"), "getFunction", byte.class));
|
165 | 164 |
|
166 |
| - access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionBoxFunctionsForReflection, |
167 |
| - ReflectionUtil.lookupMethod(ValueConversions.class, "boxExact", Wrapper.class)); |
168 |
| - |
169 |
| - access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionUnboxFunctionsForReflection, |
170 |
| - ReflectionUtil.lookupMethod(ValueConversions.class, "unbox", Wrapper.class, int.class)); |
171 |
| - |
172 |
| - access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionConvertFunctionsForReflection, |
173 |
| - ReflectionUtil.lookupMethod(ValueConversions.class, "convertPrimitive", Wrapper.class, Wrapper.class)); |
174 |
| - |
175 |
| - access.registerReachabilityHandler(MethodHandleFeature::registerValueConversionIgnoreForReflection, |
176 |
| - ReflectionUtil.lookupMethod(ValueConversions.class, "ignore")); |
| 165 | + eagerlyInitializeValueConversionsCaches(); |
177 | 166 |
|
178 | 167 | access.registerClassInitializerReachabilityHandler(MethodHandleFeature::registerDelegatingMHFunctionsForReflection,
|
179 | 168 | access.findClassByName("java.lang.invoke.DelegatingMethodHandle"));
|
@@ -328,44 +317,32 @@ private static void registerInvokersFunctionsForReflection(DuringAnalysisAccess
|
328 | 317 | RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "directVarHandleTarget", access.findClassByName("java.lang.invoke.VarHandle")));
|
329 | 318 | }
|
330 | 319 |
|
331 |
| - private static void registerValueConversionBoxFunctionsForReflection(DuringAnalysisAccess access) { |
332 |
| - for (Wrapper type : Wrapper.values()) { |
333 |
| - if (type.primitiveType().isPrimitive() && type != Wrapper.VOID) { |
334 |
| - RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "box" + type.wrapperSimpleName(), type.primitiveType())); |
335 |
| - } |
336 |
| - } |
337 |
| - } |
| 320 | + /** |
| 321 | + * Eagerly initialize method handle caches in {@link ValueConversions} so that 1) we avoid |
| 322 | + * reflection registration for conversion methods, and 2) the static analysis already sees a |
| 323 | + * consistent snapshot that does not change after analysis when the JDK needs more conversions. |
| 324 | + */ |
| 325 | + private static void eagerlyInitializeValueConversionsCaches() { |
| 326 | + ValueConversions.ignore(); |
338 | 327 |
|
339 |
| - private static void registerValueConversionUnboxFunctionsForReflection(DuringAnalysisAccess access) { |
340 |
| - for (Wrapper type : Wrapper.values()) { |
341 |
| - if (type.primitiveType().isPrimitive() && type != Wrapper.VOID) { |
342 |
| - RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "unbox" + type.wrapperSimpleName(), type.wrapperType())); |
343 |
| - RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "unbox" + type.wrapperSimpleName(), Object.class, boolean.class)); |
| 328 | + for (Wrapper src : Wrapper.values()) { |
| 329 | + if (src != Wrapper.VOID && src.primitiveType().isPrimitive()) { |
| 330 | + ValueConversions.boxExact(src); |
| 331 | + |
| 332 | + ValueConversions.unboxExact(src, false); |
| 333 | + ValueConversions.unboxExact(src, true); |
| 334 | + ValueConversions.unboxWiden(src); |
| 335 | + ValueConversions.unboxCast(src); |
344 | 336 | }
|
345 |
| - } |
346 |
| - } |
347 | 337 |
|
348 |
| - private static void registerValueConversionConvertFunctionsForReflection(DuringAnalysisAccess access) { |
349 |
| - for (Wrapper src : Wrapper.values()) { |
350 |
| - for (Wrapper dest : Wrapper.values()) { |
351 |
| - if (src != dest && src.primitiveType().isPrimitive() && src != Wrapper.VOID && dest.primitiveType().isPrimitive() && dest != Wrapper.VOID) { |
352 |
| - RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, valueConverterName(src, dest), src.primitiveType())); |
| 338 | + for (Wrapper dst : Wrapper.values()) { |
| 339 | + if (src != Wrapper.VOID && dst != Wrapper.VOID && (src == dst || (src.primitiveType().isPrimitive() && dst.primitiveType().isPrimitive()))) { |
| 340 | + ValueConversions.convertPrimitive(src, dst); |
353 | 341 | }
|
354 | 342 | }
|
355 | 343 | }
|
356 | 344 | }
|
357 | 345 |
|
358 |
| - private static String valueConverterName(Wrapper src, Wrapper dest) { |
359 |
| - String srcType = src.primitiveSimpleName(); |
360 |
| - String destType = dest.primitiveSimpleName(); |
361 |
| - /* Capitalize first letter of destination type */ |
362 |
| - return srcType + "To" + destType.substring(0, 1).toUpperCase(Locale.ROOT) + destType.substring(1); |
363 |
| - } |
364 |
| - |
365 |
| - private static void registerValueConversionIgnoreForReflection(DuringAnalysisAccess access) { |
366 |
| - RuntimeReflection.register(ReflectionUtil.lookupMethod(ValueConversions.class, "ignore", Object.class)); |
367 |
| - } |
368 |
| - |
369 | 346 | private static void registerDelegatingMHFunctionsForReflection(DuringAnalysisAccess access) {
|
370 | 347 | Class<?> delegatingMHClazz = access.findClassByName("java.lang.invoke.DelegatingMethodHandle");
|
371 | 348 | RuntimeReflection.register(ReflectionUtil.lookupMethod(delegatingMHClazz, "getTarget"));
|
|
0 commit comments