4242import java .util .List ;
4343import java .util .Objects ;
4444import java .util .Set ;
45+ import java .util .function .Consumer ;
4546import java .util .function .Predicate ;
4647import java .util .function .Supplier ;
4748import java .util .stream .Collectors ;
7172import com .oracle .svm .core .hub .PredefinedClassesSupport ;
7273import com .oracle .svm .core .jdk .StackTraceUtils ;
7374import com .oracle .svm .core .option .HostedOptionKey ;
75+ import com .oracle .svm .core .reflect .MissingReflectionRegistrationUtils ;
7476import com .oracle .svm .core .util .VMError ;
7577import com .oracle .svm .hosted .ExceptionSynthesizer ;
78+ import com .oracle .svm .hosted .FallbackFeature ;
7679import com .oracle .svm .hosted .ImageClassLoader ;
80+ import com .oracle .svm .hosted .ReachabilityRegistrationNode ;
7781import com .oracle .svm .hosted .classinitialization .ClassInitializationSupport ;
7882import com .oracle .svm .hosted .substitute .AnnotationSubstitutionProcessor ;
7983import com .oracle .svm .hosted .substitute .DeletedElementException ;
@@ -118,19 +122,21 @@ static class Options {
118122 private final ClassInitializationPlugin classInitializationPlugin ;
119123 private final AnalysisUniverse aUniverse ;
120124 private final ParsingReason reason ;
125+ private final FallbackFeature fallbackFeature ;
121126
122127 private ReflectionPlugins (ImageClassLoader imageClassLoader , SnippetReflectionProvider snippetReflection , AnnotationSubstitutionProcessor annotationSubstitutions ,
123- ClassInitializationPlugin classInitializationPlugin , AnalysisUniverse aUniverse , ParsingReason reason ) {
128+ ClassInitializationPlugin classInitializationPlugin , AnalysisUniverse aUniverse , ParsingReason reason , FallbackFeature fallbackFeature ) {
124129 this .imageClassLoader = imageClassLoader ;
125130 this .snippetReflection = snippetReflection ;
126131 this .annotationSubstitutions = annotationSubstitutions ;
127132 this .classInitializationPlugin = classInitializationPlugin ;
128133 this .aUniverse = aUniverse ;
129134 this .reason = reason ;
135+ this .fallbackFeature = fallbackFeature ;
130136 }
131137
132138 public static void registerInvocationPlugins (ImageClassLoader imageClassLoader , SnippetReflectionProvider snippetReflection , AnnotationSubstitutionProcessor annotationSubstitutions ,
133- ClassInitializationPlugin classInitializationPlugin , InvocationPlugins plugins , AnalysisUniverse aUniverse , ParsingReason reason ) {
139+ ClassInitializationPlugin classInitializationPlugin , InvocationPlugins plugins , AnalysisUniverse aUniverse , ParsingReason reason , FallbackFeature fallbackFeature ) {
134140 /*
135141 * Initialize the registry if we are during analysis. If hosted is false, i.e., we are
136142 * analyzing the static initializers, then we always intrinsify, so don't need a registry.
@@ -141,7 +147,7 @@ public static void registerInvocationPlugins(ImageClassLoader imageClassLoader,
141147 }
142148 }
143149
144- ReflectionPlugins rp = new ReflectionPlugins (imageClassLoader , snippetReflection , annotationSubstitutions , classInitializationPlugin , aUniverse , reason );
150+ ReflectionPlugins rp = new ReflectionPlugins (imageClassLoader , snippetReflection , annotationSubstitutions , classInitializationPlugin , aUniverse , reason , fallbackFeature );
145151 rp .registerMethodHandlesPlugins (plugins );
146152 rp .registerClassPlugins (plugins );
147153 }
@@ -255,6 +261,21 @@ private void registerClassPlugins(InvocationPlugins plugins) {
255261 "getField" , "getMethod" , "getConstructor" ,
256262 "getDeclaredField" , "getDeclaredMethod" , "getDeclaredConstructor" );
257263
264+ if (MissingReflectionRegistrationUtils .throwMissingRegistrationErrors ()) {
265+ registerBulkInvocationPlugin (plugins , Class .class , "getClasses" , RuntimeReflection ::registerAllClasses );
266+ registerBulkInvocationPlugin (plugins , Class .class , "getDeclaredClasses" , RuntimeReflection ::registerAllDeclaredClasses );
267+ registerBulkInvocationPlugin (plugins , Class .class , "getConstructors" , RuntimeReflection ::registerAllConstructors );
268+ registerBulkInvocationPlugin (plugins , Class .class , "getDeclaredConstructors" , RuntimeReflection ::registerAllDeclaredConstructors );
269+ registerBulkInvocationPlugin (plugins , Class .class , "getFields" , RuntimeReflection ::registerAllFields );
270+ registerBulkInvocationPlugin (plugins , Class .class , "getDeclaredFields" , RuntimeReflection ::registerAllDeclaredFields );
271+ registerBulkInvocationPlugin (plugins , Class .class , "getMethods" , RuntimeReflection ::registerAllMethods );
272+ registerBulkInvocationPlugin (plugins , Class .class , "getDeclaredMethods" , RuntimeReflection ::registerAllDeclaredMethods );
273+ registerBulkInvocationPlugin (plugins , Class .class , "getNestMembers" , RuntimeReflection ::registerAllNestMembers );
274+ registerBulkInvocationPlugin (plugins , Class .class , "getPermittedSubclasses" , RuntimeReflection ::registerAllPermittedSubclasses );
275+ registerBulkInvocationPlugin (plugins , Class .class , "getRecordComponents" , RuntimeReflection ::registerAllRecordComponents );
276+ registerBulkInvocationPlugin (plugins , Class .class , "getSigners" , RuntimeReflection ::registerAllSigners );
277+ }
278+
258279 Registration r = new Registration (plugins , Class .class );
259280 r .register (new RequiredInvocationPlugin ("forName" , String .class ) {
260281 @ Override
@@ -390,7 +411,7 @@ private void registerFoldInvocationPlugin(InvocationPlugins plugins, Method refl
390411 }
391412
392413 private void registerFoldInvocationPlugin (InvocationPlugins plugins , Method reflectionMethod , Predicate <Object []> allowConstantFolding ) {
393- if (!ALLOWED_CONSTANT_CLASSES . contains (reflectionMethod .getReturnType ()) && ! reflectionMethod . getReturnType (). isPrimitive ( )) {
414+ if (!isAllowedReturnType (reflectionMethod .getReturnType ())) {
394415 throw VMError .shouldNotReachHere ("Return type of method " + reflectionMethod + " is not on the allow-list for types that are immutable" );
395416 }
396417 reflectionMethod .setAccessible (true );
@@ -409,6 +430,10 @@ public boolean defaultHandler(GraphBuilderContext b, ResolvedJavaMethod targetMe
409430 });
410431 }
411432
433+ private static boolean isAllowedReturnType (Class <?> returnType ) {
434+ return ALLOWED_CONSTANT_CLASSES .contains (returnType ) || returnType .isPrimitive ();
435+ }
436+
412437 private boolean foldInvocationUsingReflection (GraphBuilderContext b , ResolvedJavaMethod targetMethod , Method reflectionMethod , Receiver receiver , ValueNode [] args ,
413438 Predicate <Object []> allowConstantFolding ) {
414439 assert b .getMetaAccess ().lookupJavaMethod (reflectionMethod ).equals (targetMethod ) : "Fold method mismatch: " + reflectionMethod + " != " + targetMethod ;
@@ -469,6 +494,48 @@ private boolean foldInvocationUsingReflection(GraphBuilderContext b, ResolvedJav
469494 return pushConstant (b , targetMethod , targetParameters , returnKind , returnValue , false ) != null ;
470495 }
471496
497+ private <T > void registerBulkInvocationPlugin (InvocationPlugins plugins , Class <T > declaringClass , String methodName , Consumer <T > registrationCallback ) {
498+ plugins .register (declaringClass , new RequiredInvocationPlugin (methodName , new Class <?>[]{Receiver .class }) {
499+ @ Override
500+ public boolean isDecorator () {
501+ return true ;
502+ }
503+
504+ @ Override
505+ public boolean apply (GraphBuilderContext b , ResolvedJavaMethod targetMethod , Receiver receiver ) {
506+ VMError .guarantee (!targetMethod .isStatic (), "Bulk reflection queries are not static" );
507+ return registerConstantBulkReflectionQuery (b , receiver , registrationCallback );
508+ }
509+ });
510+ }
511+
512+ @ SuppressWarnings ("unchecked" )
513+ private <T > boolean registerConstantBulkReflectionQuery (GraphBuilderContext b , Receiver receiver , Consumer <T > registrationCallback ) {
514+ /*
515+ * Calling receiver.get(true) can add a null check guard, i.e., modifying the graph in the
516+ * process. It is an error for invocation plugins that do not replace the call to modify the
517+ * graph.
518+ */
519+ Object receiverValue = unbox (b , receiver .get (false ), JavaKind .Object );
520+ if (receiverValue == null || receiverValue == NULL_MARKER ) {
521+ return false ;
522+ }
523+
524+ b .add (new ReachabilityRegistrationNode (() -> registerForRuntimeReflection ((T ) receiverValue , registrationCallback )));
525+ return true ;
526+ }
527+
528+ private <T > void registerForRuntimeReflection (T receiver , Consumer <T > registrationCallback ) {
529+ try {
530+ registrationCallback .accept (receiver );
531+ if (fallbackFeature != null ) {
532+ fallbackFeature .ignoreReflectionFallback = true ;
533+ }
534+ } catch (LinkageError e ) {
535+ // Ignore, the call should be registered manually
536+ }
537+ }
538+
472539 private static boolean shouldInitializeAtRuntime (Class <?> classArg ) {
473540 ClassInitializationSupport classInitializationSupport = (ClassInitializationSupport ) ImageSingletons .lookup (RuntimeClassInitializationSupport .class );
474541 return classInitializationSupport .shouldInitializeAtRuntime (classArg );
0 commit comments