56
56
import java .util .Arrays ;
57
57
import java .util .Collection ;
58
58
import java .util .Collections ;
59
+ import java .util .HashSet ;
59
60
import java .util .List ;
60
61
import java .util .Map ;
61
62
import java .util .Objects ;
100
101
101
102
import jdk .vm .ci .meta .ResolvedJavaField ;
102
103
import jdk .vm .ci .meta .ResolvedJavaMethod ;
103
- import jdk .vm .ci .meta .Signature ;
104
104
import sun .reflect .annotation .ExceptionProxy ;
105
105
106
106
public class ReflectionDataBuilder extends ConditionalConfigurationRegistry implements RuntimeReflectionSupport , ReflectionHostedSupport {
@@ -121,9 +121,9 @@ public class ReflectionDataBuilder extends ConditionalConfigurationRegistry impl
121
121
*/
122
122
private final Map <Class <?>, Set <Class <?>>> innerClasses = new ConcurrentHashMap <>();
123
123
private final Map <Class <?>, Integer > enabledQueriesFlags = new ConcurrentHashMap <>();
124
- private final Map <AnalysisField , ConditionalRuntimeValue <Field >> registeredFields = new ConcurrentHashMap <>();
124
+ private final Map <AnalysisType , Map < AnalysisField , ConditionalRuntimeValue <Field > >> registeredFields = new ConcurrentHashMap <>();
125
125
private final Set <AnalysisField > hidingFields = ConcurrentHashMap .newKeySet ();
126
- private final Map <AnalysisMethod , ConditionalRuntimeValue <Executable >> registeredMethods = new ConcurrentHashMap <>();
126
+ private final Map <AnalysisType , Map < AnalysisMethod , ConditionalRuntimeValue <Executable > >> registeredMethods = new ConcurrentHashMap <>();
127
127
private final Map <AnalysisMethod , Object > methodAccessors = new ConcurrentHashMap <>();
128
128
private final Set <AnalysisMethod > hidingMethods = ConcurrentHashMap .newKeySet ();
129
129
@@ -193,6 +193,10 @@ private void setQueryFlag(Class<?> clazz, int flag) {
193
193
enabledQueriesFlags .compute (clazz , (key , oldValue ) -> (oldValue == null ) ? flag : (oldValue | flag ));
194
194
}
195
195
196
+ private boolean isQueryFlagSet (Class <?> clazz , int flag ) {
197
+ return (enabledQueriesFlags .getOrDefault (clazz , 0 ) & flag ) != 0 ;
198
+ }
199
+
196
200
@ Override
197
201
public void register (ConfigurationCondition condition , boolean unsafeInstantiated , Class <?> clazz ) {
198
202
Objects .requireNonNull (clazz , () -> nullErrorMessage ("class" ));
@@ -419,11 +423,15 @@ private void registerMethod(ConfigurationCondition cnd, boolean queriedOnly, Exe
419
423
}
420
424
421
425
AnalysisMethod analysisMethod = metaAccess .lookupJavaMethod (reflectExecutable );
426
+ AnalysisType declaringType = analysisMethod .getDeclaringClass ();
427
+ var classMethods = registeredMethods .computeIfAbsent (declaringType , t -> new ConcurrentHashMap <>());
428
+ var shouldRegisterReachabilityHandler = classMethods .isEmpty ();
429
+
422
430
boolean registered = false ;
423
- ConditionalRuntimeValue <Executable > conditionalValue = registeredMethods .get (analysisMethod );
431
+ ConditionalRuntimeValue <Executable > conditionalValue = classMethods .get (analysisMethod );
424
432
if (conditionalValue == null ) {
425
433
var newConditionalValue = new ConditionalRuntimeValue <>(RuntimeConditionSet .emptySet (), reflectExecutable );
426
- conditionalValue = registeredMethods .putIfAbsent (analysisMethod , newConditionalValue );
434
+ conditionalValue = classMethods .putIfAbsent (analysisMethod , newConditionalValue );
427
435
if (conditionalValue == null ) {
428
436
conditionalValue = newConditionalValue ;
429
437
registered = true ;
@@ -436,15 +444,26 @@ private void registerMethod(ConfigurationCondition cnd, boolean queriedOnly, Exe
436
444
437
445
if (registered ) {
438
446
registerTypesForMethod (analysisMethod , reflectExecutable );
439
- AnalysisType declaringType = analysisMethod .getDeclaringClass ();
440
447
Class <?> declaringClass = declaringType .getJavaClass ();
441
448
442
449
/*
443
450
* The image needs to know about subtypes shadowing methods registered for reflection to
444
451
* ensure the correctness of run-time reflection queries.
445
452
*/
446
- analysisAccess .registerSubtypeReachabilityHandler (
447
- (access , subType ) -> universe .getBigbang ().postTask (debug -> checkSubtypeForOverridingMethod (analysisMethod , metaAccess .lookupJavaType (subType ))), declaringClass );
453
+ if (shouldRegisterReachabilityHandler ) {
454
+ analysisAccess .registerSubtypeReachabilityHandler (
455
+ (access , subType ) -> universe .getBigbang ()
456
+ .postTask (debug -> checkSubtypeForOverridingMethods (metaAccess .lookupJavaType (subType ), registeredMethods .get (declaringType ).keySet ())),
457
+ declaringClass );
458
+ } else {
459
+ /*
460
+ * We need to perform the check for already reachable subtypes since the
461
+ * reachability handler was already called for them.
462
+ */
463
+ for (AnalysisType subtype : AnalysisUniverse .reachableSubtypes (declaringType )) {
464
+ universe .getBigbang ().postTask (debug -> checkSubtypeForOverridingMethods (subtype , Collections .singleton (analysisMethod )));
465
+ }
466
+ }
448
467
449
468
if (declaringType .isAnnotation () && !analysisMethod .isConstructor ()) {
450
469
processAnnotationMethod (queriedOnly , (Method ) reflectExecutable );
@@ -552,30 +571,45 @@ private void registerField(ConfigurationCondition cnd, boolean queriedOnly, Fiel
552
571
}
553
572
554
573
AnalysisField analysisField = metaAccess .lookupJavaField (reflectField );
574
+ AnalysisType declaringClass = analysisField .getDeclaringClass ();
555
575
556
- if (!registeredFields .containsKey (analysisField )) {
576
+ var classFields = registeredFields .computeIfAbsent (declaringClass , t -> new ConcurrentHashMap <>());
577
+ boolean exists = classFields .containsKey (analysisField );
578
+ boolean shouldRegisterReachabilityHandler = classFields .isEmpty ();
579
+ var cndValue = classFields .computeIfAbsent (analysisField , f -> new ConditionalRuntimeValue <>(RuntimeConditionSet .emptySet (), reflectField ));
580
+ if (!queriedOnly ) {
581
+ /* queryOnly methods are conditioned by the type itself */
582
+ cndValue .getConditions ().addCondition (cnd );
583
+ }
584
+
585
+ if (!exists ) {
557
586
registerTypesForField (analysisField , reflectField , true );
558
- AnalysisType declaringClass = analysisField .getDeclaringClass ();
559
587
560
588
/*
561
589
* The image needs to know about subtypes shadowing fields registered for reflection to
562
590
* ensure the correctness of run-time reflection queries.
563
591
*/
564
- analysisAccess .registerSubtypeReachabilityHandler (
565
- (access , subType ) -> universe .getBigbang ().postTask (debug -> checkSubtypeForOverridingField (analysisField , metaAccess .lookupJavaType (subType ))),
566
- declaringClass .getJavaClass ());
592
+ if (shouldRegisterReachabilityHandler ) {
593
+ analysisAccess .registerSubtypeReachabilityHandler (
594
+ (access , subType ) -> universe .getBigbang ()
595
+ .postTask (debug -> checkSubtypeForOverridingFields (metaAccess .lookupJavaType (subType ),
596
+ registeredFields .get (declaringClass ).keySet ())),
597
+ declaringClass .getJavaClass ());
598
+ } else {
599
+ /*
600
+ * We need to perform the check for already reachable subtypes since the
601
+ * reachability handler was already called for them.
602
+ */
603
+ for (AnalysisType subtype : AnalysisUniverse .reachableSubtypes (declaringClass )) {
604
+ universe .getBigbang ().postTask (debug -> checkSubtypeForOverridingFields (subtype , Collections .singleton (analysisField )));
605
+ }
606
+ }
567
607
568
608
if (declaringClass .isAnnotation ()) {
569
609
processAnnotationField (cnd , reflectField );
570
610
}
571
611
}
572
612
573
- var cndValue = registeredFields .computeIfAbsent (analysisField , f -> new ConditionalRuntimeValue <>(RuntimeConditionSet .emptySet (), reflectField ));
574
- if (!queriedOnly ) {
575
- /* queryOnly methods are conditioned by the type itself */
576
- cndValue .getConditions ().addCondition (cnd );
577
- }
578
-
579
613
/*
580
614
* We need to run this even if the method has already been registered, in case it was only
581
615
* registered as queried.
@@ -635,13 +669,21 @@ private void processAnnotationField(ConfigurationCondition cnd, Field field) {
635
669
/**
636
670
* @see ReflectionHostedSupport#getHidingReflectionFields()
637
671
*/
638
- private void checkSubtypeForOverridingField (AnalysisField field , AnalysisType subtype ) {
672
+ private void checkSubtypeForOverridingFields (AnalysisType subtype , Collection <AnalysisField > superclassFields ) {
673
+ if (isQueryFlagSet (subtype .getJavaClass (), ALL_DECLARED_FIELDS_FLAG )) {
674
+ /* All fields are already registered, no need for hiding fields */
675
+ return ;
676
+ }
639
677
try {
640
- ResolvedJavaField [] subClassFields = field .isStatic () ? subtype .getStaticFields () : subtype .getInstanceFields (false );
678
+ Set <ResolvedJavaField > subClassFields = new HashSet <>();
679
+ subClassFields .addAll (Arrays .asList (subtype .getInstanceFields (false )));
680
+ subClassFields .addAll (Arrays .asList (subtype .getStaticFields ()));
641
681
for (ResolvedJavaField javaField : subClassFields ) {
642
- AnalysisField subclassField = (AnalysisField ) javaField ;
643
- if (subclassField .getName ().equals (field .getName ())) {
644
- hidingFields .add (subclassField );
682
+ for (AnalysisField registeredField : superclassFields ) {
683
+ AnalysisField subclassField = (AnalysisField ) javaField ;
684
+ if (subclassField .getName ().equals (registeredField .getName ())) {
685
+ hidingFields .add (subclassField );
686
+ }
645
687
}
646
688
}
647
689
} catch (UnsupportedFeatureException | LinkageError e ) {
@@ -653,8 +695,7 @@ private void checkSubtypeForOverridingField(AnalysisField field, AnalysisType su
653
695
}
654
696
655
697
/**
656
- * Using {@link AnalysisType#findMethod(String, Signature)} here which uses
657
- * {@link Class#getDeclaredMethods()} internally, instead of
698
+ * Filtering {@link Class#getDeclaredMethods()} here instead of directly calling
658
699
* {@link AnalysisType#resolveConcreteMethod(ResolvedJavaMethod)} which gives different results
659
700
* in at least two scenarios:
660
701
* <p>
@@ -669,11 +710,19 @@ private void checkSubtypeForOverridingField(AnalysisField field, AnalysisType su
669
710
*
670
711
* @see ReflectionHostedSupport#getHidingReflectionMethods()
671
712
*/
672
- private void checkSubtypeForOverridingMethod (AnalysisMethod method , AnalysisType subtype ) {
713
+ private void checkSubtypeForOverridingMethods (AnalysisType subtype , Collection <AnalysisMethod > superclassMethods ) {
714
+ if (isQueryFlagSet (subtype .getJavaClass (), ALL_DECLARED_METHODS_FLAG )) {
715
+ /* All methods are already registered, no need for hiding methods */
716
+ return ;
717
+ }
673
718
try {
674
- AnalysisMethod subClassMethod = subtype .findMethod (method .getName (), method .getSignature ());
675
- if (subClassMethod != null ) {
676
- hidingMethods .add (subClassMethod );
719
+ for (AnalysisMethod subClassMethod : subtype .getDeclaredMethods (false )) {
720
+ for (AnalysisMethod registeredMethod : superclassMethods ) {
721
+ if (registeredMethod .getName ().equals (subClassMethod .getName ()) &&
722
+ registeredMethod .getSignature ().equals (subClassMethod .getSignature ())) {
723
+ hidingMethods .add (subClassMethod );
724
+ }
725
+ }
677
726
}
678
727
} catch (UnsupportedFeatureException | LinkageError e ) {
679
728
/*
@@ -1040,7 +1089,8 @@ private void maybeRegisterRecordComponents(Class<?> clazz) {
1040
1089
}
1041
1090
pendingRecordClasses .put (clazz , unregisteredAccessors );
1042
1091
1043
- unregisteredAccessors .removeIf (accessor -> registeredMethods .containsKey (metaAccess .lookupJavaMethod (accessor )));
1092
+ AnalysisType analysisType = metaAccess .lookupJavaType (clazz );
1093
+ unregisteredAccessors .removeIf (accessor -> registeredMethods .getOrDefault (analysisType , Collections .emptyMap ()).containsKey (metaAccess .lookupJavaMethod (accessor )));
1044
1094
if (unregisteredAccessors .isEmpty ()) {
1045
1095
registerRecordComponents (clazz );
1046
1096
}
@@ -1091,13 +1141,13 @@ public int getEnabledReflectionQueries(Class<?> clazz) {
1091
1141
}
1092
1142
1093
1143
@ Override
1094
- public Map <AnalysisField , ConditionalRuntimeValue <Field >> getReflectionFields () {
1144
+ public Map <AnalysisType , Map < AnalysisField , ConditionalRuntimeValue <Field > >> getReflectionFields () {
1095
1145
assert sealed ;
1096
1146
return Collections .unmodifiableMap (registeredFields );
1097
1147
}
1098
1148
1099
1149
@ Override
1100
- public Map <AnalysisMethod , ConditionalRuntimeValue <Executable >> getReflectionExecutables () {
1150
+ public Map <AnalysisType , Map < AnalysisMethod , ConditionalRuntimeValue <Executable > >> getReflectionExecutables () {
1101
1151
assert sealed ;
1102
1152
return Collections .unmodifiableMap (registeredMethods );
1103
1153
}
0 commit comments