diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java index aa5d67560ee9..485fc871aeb9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java @@ -27,12 +27,11 @@ import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; -import java.lang.reflect.Array; +import java.lang.invoke.VarHandle; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import java.lang.reflect.Method; -import java.util.Iterator; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; @@ -108,20 +107,20 @@ public class MethodHandleFeature implements InternalFeature { @Override public void duringSetup(DuringSetupAccess access) { - Class memberNameClass = access.findClassByName("java.lang.invoke.MemberName"); + Class memberNameClass = ReflectionUtil.lookupClass("java.lang.invoke.MemberName"); memberNameIsMethod = ReflectionUtil.lookupMethod(memberNameClass, "isMethod"); memberNameIsConstructor = ReflectionUtil.lookupMethod(memberNameClass, "isConstructor"); memberNameIsField = ReflectionUtil.lookupMethod(memberNameClass, "isField"); memberNameGetMethodType = ReflectionUtil.lookupMethod(memberNameClass, "getMethodType"); - Class arrayAccessorClass = access.findClassByName("java.lang.invoke.MethodHandleImpl$ArrayAccessor"); + Class arrayAccessorClass = ReflectionUtil.lookupClass("java.lang.invoke.MethodHandleImpl$ArrayAccessor"); typedAccessors = ReflectionUtil.lookupField(arrayAccessorClass, "TYPED_ACCESSORS"); - Class methodHandleImplClass = access.findClassByName("java.lang.invoke.MethodHandleImpl$Makers"); - typedCollectors = ReflectionUtil.lookupField(methodHandleImplClass, "TYPED_COLLECTORS"); + Class makersClass = ReflectionUtil.lookupClass("java.lang.invoke.MethodHandleImpl$Makers"); + typedCollectors = ReflectionUtil.lookupField(makersClass, "TYPED_COLLECTORS"); if (JavaVersionUtil.JAVA_SPEC >= 22) { try { - Class referencedKeySetClass = access.findClassByName("jdk.internal.util.ReferencedKeySet"); + Class referencedKeySetClass = ReflectionUtil.lookupClass("jdk.internal.util.ReferencedKeySet"); Method create = ReflectionUtil.lookupMethod(referencedKeySetClass, "create", boolean.class, boolean.class, Supplier.class); // The following call must match the static initializer of MethodType#internTable. runtimeMethodTypeInternTable = create.invoke(null, @@ -131,7 +130,7 @@ public void duringSetup(DuringSetupAccess access) { throw VMError.shouldNotReachHere(e); } } else { - Class concurrentWeakInternSetClass = access.findClassByName("java.lang.invoke.MethodType$ConcurrentWeakInternSet"); + Class concurrentWeakInternSetClass = ReflectionUtil.lookupClass("java.lang.invoke.MethodType$ConcurrentWeakInternSet"); runtimeMethodTypeInternTable = ReflectionUtil.newInstance(concurrentWeakInternSetClass); referencedKeySetAdd = ReflectionUtil.lookupMethod(concurrentWeakInternSetClass, "add", Object.class); } @@ -148,45 +147,22 @@ public void duringSetup(DuringSetupAccess access) { public void beforeAnalysis(BeforeAnalysisAccess a) { var access = (BeforeAnalysisAccessImpl) a; - /* java.lang.invoke functions called through reflection */ - Class mhImplClazz = access.findClassByName("java.lang.invoke.MethodHandleImpl"); - - access.registerReachabilityHandler(MethodHandleFeature::registerMHImplFunctionsForReflection, - ReflectionUtil.lookupMethod(mhImplClazz, "getFunction", byte.class)); - - access.registerReachabilityHandler(MethodHandleFeature::registerMHImplConstantHandlesForReflection, - ReflectionUtil.lookupMethod(mhImplClazz, "makeConstantHandle", int.class)); - - access.registerReachabilityHandler(MethodHandleFeature::registerMHImplCountingWrapperFunctionsForReflection, - access.findClassByName("java.lang.invoke.MethodHandleImpl$CountingWrapper")); - - access.registerReachabilityHandler(MethodHandleFeature::registerInvokersFunctionsForReflection, - ReflectionUtil.lookupMethod(access.findClassByName("java.lang.invoke.Invokers"), "getFunction", byte.class)); - + eagerlyInitializeMHImplFunctions(); + eagerlyInitializeMHImplConstantHandles(); + eagerlyInitializeInvokersFunctions(); eagerlyInitializeValueConversionsCaches(); + eagerlyInitializeCallSite(); - access.registerClassInitializerReachabilityHandler(MethodHandleFeature::registerDelegatingMHFunctionsForReflection, - access.findClassByName("java.lang.invoke.DelegatingMethodHandle")); - - access.registerReachabilityHandler(MethodHandleFeature::registerCallSiteGetTargetForReflection, - ReflectionUtil.lookupMethod(CallSite.class, "getTargetHandle")); - - access.registerReachabilityHandler(MethodHandleFeature::registerUninitializedCallSiteForReflection, - ReflectionUtil.lookupMethod(CallSite.class, "uninitializedCallSiteHandle")); - - access.registerSubtypeReachabilityHandler(MethodHandleFeature::registerVarHandleMethodsForReflection, - access.findClassByName("java.lang.invoke.VarHandle")); - - access.registerSubtypeReachabilityHandler(MethodHandleFeature::scanBoundMethodHandle, - access.findClassByName("java.lang.invoke.BoundMethodHandle")); + access.registerSubtypeReachabilityHandler(MethodHandleFeature::registerVarHandleMethodsForReflection, VarHandle.class); + access.registerSubtypeReachabilityHandler(MethodHandleFeature::scanBoundMethodHandle, ReflectionUtil.lookupClass("java.lang.invoke.BoundMethodHandle")); AnalysisMetaAccess metaAccess = access.getMetaAccess(); ImageHeapScanner heapScanner = access.getUniverse().getHeapScanner(); access.registerFieldValueTransformer( - ReflectionUtil.lookupField(ReflectionUtil.lookupClass(false, "java.lang.invoke.ClassSpecializer"), "cache"), + ReflectionUtil.lookupField(ReflectionUtil.lookupClass("java.lang.invoke.ClassSpecializer"), "cache"), new FieldValueTransformerWithAvailability() { - private static final Class speciesDataClass = ReflectionUtil.lookupClass(false, "java.lang.invoke.ClassSpecializer$SpeciesData"); + private static final Class SPECIES_DATA_CLASS = ReflectionUtil.lookupClass("java.lang.invoke.ClassSpecializer$SpeciesData"); /* * The value of the ClassSpecializer.cache is not seen by the analysis @@ -215,16 +191,16 @@ public Object transform(Object receiver, Object originalValue) { } private boolean isSpeciesTypeInstantiated(Object speciesData) { - Class speciesClass = ReflectionUtil.readField(speciesDataClass, "speciesCode", speciesData); + Class speciesClass = ReflectionUtil.readField(SPECIES_DATA_CLASS, "speciesCode", speciesData); Optional analysisType = metaAccess.optionalLookupJavaType(speciesClass); return analysisType.isPresent() && analysisType.get().isInstantiated(); } }); access.registerFieldValueTransformer( - ReflectionUtil.lookupField(ReflectionUtil.lookupClass(false, "java.lang.invoke.DirectMethodHandle"), "ACCESSOR_FORMS"), + ReflectionUtil.lookupField(ReflectionUtil.lookupClass("java.lang.invoke.DirectMethodHandle"), "ACCESSOR_FORMS"), NewEmptyArrayFieldValueTransformer.INSTANCE); access.registerFieldValueTransformer( - ReflectionUtil.lookupField(ReflectionUtil.lookupClass(false, "java.lang.invoke.MethodType"), "internTable"), + ReflectionUtil.lookupField(ReflectionUtil.lookupClass("java.lang.invoke.MethodType"), "internTable"), (receiver, originalValue) -> runtimeMethodTypeInternTable); /* @@ -236,7 +212,7 @@ private boolean isSpeciesTypeInstantiated(Object speciesData) { * be made reachable after analysis. */ access.registerFieldValueTransformer( - ReflectionUtil.lookupField(ReflectionUtil.lookupClass(false, "java.lang.invoke.ClassSpecializer$SpeciesData"), "transformHelpers"), + ReflectionUtil.lookupField(ReflectionUtil.lookupClass("java.lang.invoke.ClassSpecializer$SpeciesData"), "transformHelpers"), new FieldValueTransformerWithAvailability() { @Override public boolean isAvailable() { @@ -267,8 +243,8 @@ public Object transform(Object receiver, Object originalValue) { * method Feature.beforeCompilation()), thereby registering new elements into the image heap * (elements that were not tracked in the analysis). */ - Class lambdaFormClass = ReflectionUtil.lookupClass(false, "java.lang.invoke.LambdaForm"); - Class basicTypeClass = ReflectionUtil.lookupClass(false, "java.lang.invoke.LambdaForm$BasicType"); + Class lambdaFormClass = ReflectionUtil.lookupClass("java.lang.invoke.LambdaForm"); + Class basicTypeClass = ReflectionUtil.lookupClass("java.lang.invoke.LambdaForm$BasicType"); Method createFormsForMethod = ReflectionUtil.lookupMethod(lambdaFormClass, "createFormsFor", basicTypeClass); try { for (Object type : (Object[]) ReflectionUtil.readStaticField(basicTypeClass, "ALL_TYPES")) { @@ -279,43 +255,31 @@ public Object transform(Object receiver, Object originalValue) { } } - private static void registerMHImplFunctionsForReflection(DuringAnalysisAccess access) { - Class mhImplClazz = access.findClassByName("java.lang.invoke.MethodHandleImpl"); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "checkSpreadArgument", Object.class, int.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "guardWithCatch", MethodHandle.class, Class.class, MethodHandle.class, Object[].class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "tryFinally", MethodHandle.class, MethodHandle.class, Object[].class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "loop", access.findClassByName("[Ljava.lang.invoke.LambdaForm$BasicType;"), - access.findClassByName("java.lang.invoke.MethodHandleImpl$LoopClauses"), Object[].class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "throwException", Throwable.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "profileBoolean", boolean.class, int[].class)); - } - - private static void registerMHImplConstantHandlesForReflection(DuringAnalysisAccess access) { - Class mhImplClazz = access.findClassByName("java.lang.invoke.MethodHandleImpl"); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "selectAlternative", boolean.class, MethodHandle.class, MethodHandle.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "countedLoopPredicate", int.class, int.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "countedLoopStep", int.class, int.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "initIterator", Iterable.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "iteratePredicate", Iterator.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "iterateNext", Iterator.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(Array.class, "newInstance", Class.class, int.class)); + private static void eagerlyInitializeMHImplFunctions() { + var methodHandleImplClass = ReflectionUtil.lookupClass("java.lang.invoke.MethodHandleImpl"); + int count = ((Object[]) ReflectionUtil.readStaticField(methodHandleImplClass, "NFS")).length; + var getFunctionMethod = ReflectionUtil.lookupMethod(methodHandleImplClass, "getFunction", byte.class); + for (int i = 0; i < count; i++) { + ReflectionUtil.invokeMethod(getFunctionMethod, null, (byte) i); + } } - private static void registerMHImplCountingWrapperFunctionsForReflection(DuringAnalysisAccess access) { - RuntimeReflection.register(ReflectionUtil.lookupMethod(access.findClassByName("java.lang.invoke.MethodHandleImpl$CountingWrapper"), "maybeStopCounting", Object.class)); + private static void eagerlyInitializeMHImplConstantHandles() { + var methodHandleImplClass = ReflectionUtil.lookupClass("java.lang.invoke.MethodHandleImpl"); + int count = ((Object[]) ReflectionUtil.readStaticField(methodHandleImplClass, "HANDLES")).length; + var getConstantHandleMethod = ReflectionUtil.lookupMethod(methodHandleImplClass, "getConstantHandle", int.class); + for (int i = 0; i < count; i++) { + ReflectionUtil.invokeMethod(getConstantHandleMethod, null, i); + } } - private static void registerInvokersFunctionsForReflection(DuringAnalysisAccess access) { - Class invokersClazz = access.findClassByName("java.lang.invoke.Invokers"); - RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "checkExactType", MethodHandle.class, MethodType.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "checkGenericType", MethodHandle.class, MethodType.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "getCallSiteTarget", CallSite.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "checkCustomized", MethodHandle.class)); - RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "checkVarHandleGenericType", access.findClassByName("java.lang.invoke.VarHandle"), - access.findClassByName("java.lang.invoke.VarHandle$AccessDescriptor"))); - RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "checkVarHandleExactType", access.findClassByName("java.lang.invoke.VarHandle"), - access.findClassByName("java.lang.invoke.VarHandle$AccessDescriptor"))); - RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "directVarHandleTarget", access.findClassByName("java.lang.invoke.VarHandle"))); + private static void eagerlyInitializeInvokersFunctions() { + var invokerksClass = ReflectionUtil.lookupClass("java.lang.invoke.Invokers"); + int count = ((Object[]) ReflectionUtil.readStaticField(invokerksClass, "NFS")).length; + var getFunctionMethod = ReflectionUtil.lookupMethod(invokerksClass, "getFunction", byte.class); + for (int i = 0; i < count; i++) { + ReflectionUtil.invokeMethod(getFunctionMethod, null, (byte) i); + } } /** @@ -344,21 +308,13 @@ private static void eagerlyInitializeValueConversionsCaches() { } } - private static void registerDelegatingMHFunctionsForReflection(DuringAnalysisAccess access) { - Class delegatingMHClazz = access.findClassByName("java.lang.invoke.DelegatingMethodHandle"); - RuntimeReflection.register(ReflectionUtil.lookupMethod(delegatingMHClazz, "getTarget")); - } - - private static void registerCallSiteGetTargetForReflection(DuringAnalysisAccess access) { - RuntimeReflection.register(ReflectionUtil.lookupMethod(CallSite.class, "getTarget")); - } - - private static void registerUninitializedCallSiteForReflection(DuringAnalysisAccess access) { - RuntimeReflection.register(ReflectionUtil.lookupMethod(CallSite.class, "uninitializedCallSite", Object[].class)); + private static void eagerlyInitializeCallSite() { + ReflectionUtil.invokeMethod(ReflectionUtil.lookupMethod(CallSite.class, "getTargetHandle"), null); + ReflectionUtil.invokeMethod(ReflectionUtil.lookupMethod(CallSite.class, "uninitializedCallSiteHandle"), null); } private static void registerVarHandleMethodsForReflection(FeatureAccess access, Class subtype) { - if (subtype.getPackage().getName().equals("java.lang.invoke") && subtype != access.findClassByName("java.lang.invoke.VarHandle")) { + if (subtype.getPackage().getName().equals("java.lang.invoke") && subtype != VarHandle.class) { RuntimeReflection.register(subtype.getDeclaredMethods()); } }