4040import static org .graalvm .nativeimage .dynamicaccess .AccessCondition .unconditional ;
4141
4242import java .lang .annotation .AnnotationFormatError ;
43+ import java .lang .reflect .AnnotatedElement ;
4344import java .lang .reflect .Constructor ;
4445import java .lang .reflect .Executable ;
4546import java .lang .reflect .Field ;
8586import com .oracle .graal .pointsto .meta .AnalysisMethod ;
8687import com .oracle .graal .pointsto .meta .AnalysisType ;
8788import com .oracle .graal .pointsto .meta .AnalysisUniverse ;
88- import com .oracle .svm .core .FutureDefaultsOptions ;
8989import com .oracle .svm .core .MissingRegistrationUtils ;
9090import com .oracle .svm .core .configure .ConditionalRuntimeValue ;
9191import com .oracle .svm .core .configure .RuntimeDynamicAccessMetadata ;
@@ -150,12 +150,15 @@ public class ReflectionDataBuilder extends ConditionalConfigurationRegistry impl
150150 */
151151 private final Map <Class <?>, Set <Class <?>>> innerClasses = new ConcurrentHashMap <>();
152152 private final Map <Class <?>, Integer > enabledQueriesFlags = new ConcurrentHashMap <>();
153- private final Map <AnalysisType , Map <AnalysisField , ConditionalRuntimeValue <Field >>> registeredFields = new ConcurrentHashMap <>();
153+ private final Map <AnalysisType , Map <AnalysisField , RegisteredMemberData <Field >>> registeredFields = new ConcurrentHashMap <>();
154154 private final Set <AnalysisField > hidingFields = ConcurrentHashMap .newKeySet ();
155- private final Map <AnalysisType , Map <AnalysisMethod , ConditionalRuntimeValue <Executable >>> registeredMethods = new ConcurrentHashMap <>();
155+ private final Map <AnalysisType , Map <AnalysisMethod , RegisteredMemberData <Executable >>> registeredMethods = new ConcurrentHashMap <>();
156156 private final Map <AnalysisMethod , Object > methodAccessors = new ConcurrentHashMap <>();
157157 private final Set <AnalysisMethod > hidingMethods = ConcurrentHashMap .newKeySet ();
158158
159+ private record RegisteredMemberData <T extends AnnotatedElement >(ConditionalRuntimeValue <T > member , boolean queriedOnly ) {
160+ }
161+
159162 // Heap reflection data
160163 private final Set <DynamicHub > heapDynamicHubs = ConcurrentHashMap .newKeySet ();
161164 private final Map <AnalysisField , Field > heapFields = new ConcurrentHashMap <>();
@@ -222,9 +225,7 @@ public void register(AccessCondition condition, boolean preserved, Class<?> claz
222225 Objects .requireNonNull (clazz , () -> nullErrorMessage ("class" , "reflection" ));
223226 runConditionalInAnalysisTask (condition , (cnd ) -> {
224227 registerClass (cnd , clazz , true , preserved );
225- if (FutureDefaultsOptions .completeReflectionTypes ()) {
226- registerClassMetadata (cnd , clazz );
227- }
228+ registerClassMetadata (cnd , clazz , preserved );
228229 });
229230 }
230231
@@ -246,18 +247,18 @@ public void registerAllClassesQuery(AccessCondition condition, boolean preserved
246247 });
247248 }
248249
249- public void registerClassMetadata (AccessCondition condition , Class <?> clazz ) {
250- registerAllDeclaredFieldsQuery (condition , true , false , clazz );
251- registerAllFieldsQuery (condition , true , false , clazz );
252- registerAllDeclaredMethodsQuery (condition , true , false , clazz );
253- registerAllMethodsQuery (condition , true , false , clazz );
254- registerAllDeclaredConstructorsQuery (condition , true , false , clazz );
255- registerAllConstructorsQuery (condition , true , false , clazz );
256- registerAllDeclaredClassesQuery (condition , false , clazz );
257- registerAllClassesQuery (condition , false , clazz );
250+ public void registerClassMetadata (AccessCondition condition , Class <?> clazz , boolean preserved ) {
251+ registerAllDeclaredFieldsQuery (condition , true , preserved , clazz );
252+ registerAllFieldsQuery (condition , true , preserved , clazz );
253+ registerAllDeclaredMethodsQuery (condition , true , preserved , clazz );
254+ registerAllMethodsQuery (condition , true , preserved , clazz );
255+ registerAllDeclaredConstructorsQuery (condition , true , preserved , clazz );
256+ registerAllConstructorsQuery (condition , true , preserved , clazz );
257+ registerAllDeclaredClassesQuery (condition , preserved , clazz );
258+ registerAllClassesQuery (condition , preserved , clazz );
258259 registerAllRecordComponentsQuery (condition , clazz );
259- registerAllPermittedSubclassesQuery (condition , false , clazz );
260- registerAllNestMembersQuery (condition , false , clazz );
260+ registerAllPermittedSubclassesQuery (condition , preserved , clazz );
261+ registerAllNestMembersQuery (condition , preserved , clazz );
261262 registerAllSignersQuery (condition , clazz );
262263 }
263264
@@ -466,24 +467,29 @@ private void registerMethod(AccessCondition cnd, boolean queriedOnly, boolean pr
466467 var classMethods = registeredMethods .computeIfAbsent (declaringType , _ -> new ConcurrentHashMap <>());
467468 var shouldRegisterReachabilityHandler = classMethods .isEmpty ();
468469
469- boolean registered = false ;
470- ConditionalRuntimeValue <Executable > conditionalValue = classMethods .get (analysisMethod );
471- if (conditionalValue == null ) {
472- var newConditionalValue = new ConditionalRuntimeValue <>(RuntimeDynamicAccessMetadata .emptySet (preserved ), reflectExecutable );
473- conditionalValue = classMethods .putIfAbsent (analysisMethod , newConditionalValue );
474- if (conditionalValue == null ) {
475- conditionalValue = newConditionalValue ;
476- registered = true ;
470+ boolean exists = classMethods .containsKey (analysisMethod );
471+ ConditionalRuntimeValue <Executable > conditionalValue = classMethods .compute (analysisMethod , (_ , methodData ) -> {
472+ if (methodData == null || (methodData .queriedOnly () && !queriedOnly )) {
473+ /*
474+ * The dynamic access metadata needs to be reset when registering a queried-only
475+ * element as accessed.
476+ */
477+ return new RegisteredMemberData <>(new ConditionalRuntimeValue <>(RuntimeDynamicAccessMetadata .emptySet (preserved ), reflectExecutable ), queriedOnly );
478+ } else {
479+ if (!preserved && methodData .queriedOnly () == queriedOnly ) {
480+ var value = methodData .member ();
481+ value .getDynamicAccessMetadata ().setNotPreserved ();
482+ }
483+ return methodData ;
477484 }
478- } else if (!preserved ) {
479- conditionalValue .getDynamicAccessMetadata ().setNotPreserved ();
480- }
485+ }).member ();
486+
481487 if (!queriedOnly ) {
482488 /* queryOnly methods are conditioned by the type itself */
483489 conditionalValue .getDynamicAccessMetadata ().addCondition (cnd );
484490 }
485491
486- if (registered ) {
492+ if (! exists ) {
487493 registerTypesForMethod (analysisMethod , reflectExecutable );
488494 Class <?> declaringClass = declaringType .getJavaClass ();
489495
@@ -642,12 +648,24 @@ private void registerField(AccessCondition cnd, boolean queriedOnly, boolean pre
642648 var classFields = registeredFields .computeIfAbsent (declaringClass , _ -> new ConcurrentHashMap <>());
643649 boolean exists = classFields .containsKey (analysisField );
644650 boolean shouldRegisterReachabilityHandler = classFields .isEmpty ();
645- var cndValue = classFields .computeIfAbsent (analysisField , _ -> new ConditionalRuntimeValue <>(RuntimeDynamicAccessMetadata .emptySet (preserved ), reflectField ));
646- if (exists ) {
647- if (!preserved ) {
648- cndValue .getDynamicAccessMetadata ().setNotPreserved ();
651+
652+ ConditionalRuntimeValue <Field > cndValue = classFields .compute (analysisField , (_ , fieldData ) -> {
653+ if (fieldData == null || (fieldData .queriedOnly () && !queriedOnly )) {
654+ /*
655+ * The dynamic access metadata needs to be reset when registering an element as
656+ * accessed
657+ */
658+ return new RegisteredMemberData <>(new ConditionalRuntimeValue <>(RuntimeDynamicAccessMetadata .emptySet (preserved ), reflectField ), queriedOnly );
659+ } else {
660+ if (!preserved && fieldData .queriedOnly () == queriedOnly ) {
661+ var value = fieldData .member ();
662+ value .getDynamicAccessMetadata ().setNotPreserved ();
663+ }
664+ return fieldData ;
649665 }
650- } else {
666+ }).member ();
667+
668+ if (!exists ) {
651669 registerTypesForField (analysisField , reflectField , queriedOnly );
652670
653671 /*
@@ -1269,13 +1287,23 @@ public int getEnabledReflectionQueries(Class<?> clazz) {
12691287 @ Override
12701288 public Map <AnalysisType , Map <AnalysisField , ConditionalRuntimeValue <Field >>> getReflectionFields () {
12711289 assert isSealed ();
1272- return Collections . unmodifiableMap (registeredFields );
1290+ return filterRegisteredMemberData (registeredFields );
12731291 }
12741292
12751293 @ Override
12761294 public Map <AnalysisType , Map <AnalysisMethod , ConditionalRuntimeValue <Executable >>> getReflectionExecutables () {
12771295 assert isSealed ();
1278- return Collections .unmodifiableMap (registeredMethods );
1296+ return filterRegisteredMemberData (registeredMethods );
1297+ }
1298+
1299+ private static <A , R extends AnnotatedElement > Map <AnalysisType , Map <A , ConditionalRuntimeValue <R >>> filterRegisteredMemberData (Map <AnalysisType , Map <A , RegisteredMemberData <R >>> map ) {
1300+ /*
1301+ * Return only the ConditionalRuntimeValue, the queriedOnly boolean is not relevant once the
1302+ * builder is sealed.
1303+ */
1304+ return map .entrySet ().stream ().collect (
1305+ Collectors .toUnmodifiableMap (Map .Entry ::getKey , e -> e .getValue ().entrySet ().stream ().collect (
1306+ Collectors .toUnmodifiableMap (Map .Entry ::getKey , e2 -> e2 .getValue ().member ()))));
12791307 }
12801308
12811309 @ Override
0 commit comments