34
34
import java .util .ArrayList ;
35
35
import java .util .Collection ;
36
36
import java .util .Collections ;
37
+ import java .util .HashSet ;
37
38
import java .util .List ;
38
39
import java .util .Map ;
39
40
import java .util .Set ;
@@ -107,6 +108,9 @@ public abstract class AnalysisMethod extends AnalysisElement implements WrappedJ
107
108
private static final AtomicReferenceFieldUpdater <AnalysisMethod , Object > isInlinedUpdater = AtomicReferenceFieldUpdater
108
109
.newUpdater (AnalysisMethod .class , Object .class , "isInlined" );
109
110
111
+ static final AtomicReferenceFieldUpdater <AnalysisMethod , Object > allImplementationsUpdater = AtomicReferenceFieldUpdater
112
+ .newUpdater (AnalysisMethod .class , Object .class , "allImplementations" );
113
+
110
114
public record Signature (String name , AnalysisType [] parameterTypes ) {
111
115
}
112
116
@@ -120,6 +124,7 @@ public record Signature(String name, AnalysisType[] parameterTypes) {
120
124
private final LocalVariableTable localVariableTable ;
121
125
private final String name ;
122
126
private final String qualifiedName ;
127
+ private final int modifiers ;
123
128
124
129
protected final AnalysisType declaringClass ;
125
130
protected final ResolvedSignature <AnalysisType > signature ;
@@ -164,10 +169,12 @@ public record Signature(String name, AnalysisType[] parameterTypes) {
164
169
private EncodedGraph analyzedGraph ;
165
170
166
171
/**
167
- * All concrete methods that can actually be called when calling this method. This includes all
168
- * overridden methods in subclasses, as well as this method if it is non-abstract.
172
+ * Concrete methods that could possibly be called when calling this method. This also includes
173
+ * methods that are not reachable yet, i.e., this set must be filtered before it can be used. It
174
+ * never includes the method itself to reduce the size. See
175
+ * {@link AnalysisMethod#collectMethodImplementations} for more details.
169
176
*/
170
- protected AnalysisMethod [] implementations ;
177
+ @ SuppressWarnings ( "unused" ) private volatile Object allImplementations ;
171
178
172
179
/**
173
180
* Indicates that this method returns all instantiated types. This is necessary when there are
@@ -189,6 +196,7 @@ protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped,
189
196
190
197
name = createName (wrapped , multiMethodKey );
191
198
qualifiedName = format ("%H.%n(%P)" );
199
+ modifiers = wrapped .getModifiers ();
192
200
193
201
if (universe .hostVM ().useBaseLayer ()) {
194
202
int mid = universe .getImageLayerLoader ().lookupHostedMethodInBaseLayer (this );
@@ -258,6 +266,7 @@ protected AnalysisMethod(AnalysisMethod original, MultiMethodKey multiMethodKey)
258
266
259
267
name = createName (wrapped , multiMethodKey );
260
268
qualifiedName = format ("%H.%n(%P)" );
269
+ modifiers = original .modifiers ;
261
270
262
271
this .multiMethodKey = multiMethodKey ;
263
272
assert original .multiMethodMap != null ;
@@ -550,81 +559,10 @@ public void onImplementationInvoked() {
550
559
@ Override
551
560
public void onReachable () {
552
561
notifyReachabilityCallbacks (declaringClass .getUniverse (), new ArrayList <>());
553
- processMethodOverrides ();
554
- }
555
-
556
- private void processMethodOverrides () {
557
- if (wrapped .canBeStaticallyBound () || isConstructor ()) {
558
- notifyMethodOverride (this );
559
- } else if (declaringClass .isAnySubtypeInstantiated ()) {
560
- /*
561
- * If neither the declaring class nor a subtype is instantiated then this method cannot
562
- * be marked as invoked, so it cannot be an override.
563
- */
564
- declaringClass .forAllSuperTypes (superType -> {
565
- /*
566
- * Iterate all the super types (including this type itself) looking for installed
567
- * override notifications. If this method is found in a super type, and it has an
568
- * override handler installed in that type, pass this method to the callback. It
569
- * doesn't matter if the superMethod is actually reachable, only if it has any
570
- * override handlers installed. Note that ResolvedJavaType.resolveMethod() cannot be
571
- * used here because it only resolves methods declared by the type itself or if the
572
- * method's declaring class is assignable from the type.
573
- */
574
- AnalysisMethod superMethod = findInType (superType );
575
- if (superMethod != null ) {
576
- superMethod .notifyMethodOverride (AnalysisMethod .this );
577
- }
578
- });
579
- }
580
- }
581
-
582
- /** Find if the type declares a method with the same name and signature as this method. */
583
- private AnalysisMethod findInType (AnalysisType type ) {
584
- try {
585
- return type .findMethod (wrapped .getName (), getSignature ());
586
- } catch (UnsupportedFeatureException | LinkageError e ) {
587
- /* Ignore linking errors and deleted methods. */
588
- return null ;
589
- }
590
- }
591
-
592
- protected void notifyMethodOverride (AnalysisMethod override ) {
593
- declaringClass .getOverrideReachabilityNotifications (this ).forEach (n -> n .notifyCallback (getUniverse (), override ));
594
562
}
595
563
596
564
public void registerOverrideReachabilityNotification (MethodOverrideReachableNotification notification ) {
597
- declaringClass .registerOverrideReachabilityNotification (this , notification );
598
- }
599
-
600
- /**
601
- * Resolves this method in the provided type, but only if the type or any of its subtypes is
602
- * marked as instantiated.
603
- */
604
- protected AnalysisMethod resolveInType (AnalysisType holder ) {
605
- return resolveInType (holder , holder .isAnySubtypeInstantiated ());
606
- }
607
-
608
- protected AnalysisMethod resolveInType (AnalysisType holder , boolean holderOrSubtypeInstantiated ) {
609
- /*
610
- * If the holder and all subtypes are not instantiated, then we do not need to resolve the
611
- * method. The method cannot be marked as invoked.
612
- */
613
- if (holderOrSubtypeInstantiated || isIntrinsicMethod ()) {
614
- AnalysisMethod resolved ;
615
- try {
616
- resolved = holder .resolveConcreteMethod (this , null );
617
- } catch (UnsupportedFeatureException e ) {
618
- /* An unsupported overriding method is not reachable. */
619
- resolved = null ;
620
- }
621
- /*
622
- * resolved == null means that the method in the base class was called, but never with
623
- * this holder.
624
- */
625
- return resolved ;
626
- }
627
- return null ;
565
+ getUniverse ().registerOverrideReachabilityNotification (this , notification );
628
566
}
629
567
630
568
@ Override
@@ -699,7 +637,7 @@ public Parameter[] getParameters() {
699
637
700
638
@ Override
701
639
public int getModifiers () {
702
- return wrapped . getModifiers () ;
640
+ return modifiers ;
703
641
}
704
642
705
643
@ Override
@@ -735,12 +673,46 @@ public boolean canBeStaticallyBound() {
735
673
736
674
}
737
675
738
- public AnalysisMethod [] getImplementations () {
739
- assert getUniverse ().analysisDataValid : this ;
740
- if (implementations == null ) {
741
- return new AnalysisMethod [0 ];
676
+ /**
677
+ * Returns all methods that override (= implement) this method. If the
678
+ * {@code includeInlinedMethods} parameter is true, all reachable overrides are returned; if it
679
+ * is false, only invoked methods are returned (and methods that are already inlined at all call
680
+ * sites are excluded).
681
+ *
682
+ * In the parallel static analysis, it is difficult to have this information always available:
683
+ * when a method becomes reachable or invoked, it is not known which other methods it overrides.
684
+ * Therefore, we collect all possible implementations in {@link #allImplementations} without
685
+ * taking reachability into account, and then filter this too-large set of methods here on
686
+ * demand.
687
+ */
688
+ public Set <AnalysisMethod > collectMethodImplementations (boolean includeInlinedMethods ) {
689
+ /*
690
+ * To keep the allImplementations set as small as possible (and empty for most methods), the
691
+ * set never includes this method itself. It is clear that every method is always an
692
+ * implementation of itself.
693
+ */
694
+ boolean includeOurselfs = (isStatic () || getDeclaringClass ().isAnySubtypeInstantiated ()) &&
695
+ (includeInlinedMethods ? isReachable () : isImplementationInvoked ());
696
+
697
+ int allImplementationsSize = ConcurrentLightHashSet .size (this , allImplementationsUpdater );
698
+ if (allImplementationsSize == 0 ) {
699
+ /* Fast-path that avoids allocation of a full HashSet. */
700
+ return includeOurselfs ? Set .of (this ) : Set .of ();
701
+ }
702
+
703
+ Set <AnalysisMethod > result = new HashSet <>(allImplementationsSize + 1 );
704
+ if (includeOurselfs ) {
705
+ result .add (this );
742
706
}
743
- return implementations ;
707
+ ConcurrentLightHashSet .forEach (this , allImplementationsUpdater , (AnalysisMethod override ) -> {
708
+ if (override .getDeclaringClass ().isAnySubtypeInstantiated ()) {
709
+ if (includeInlinedMethods ? override .isReachable () : override .isImplementationInvoked ()) {
710
+ result .add (override );
711
+ }
712
+ }
713
+ });
714
+
715
+ return result ;
744
716
}
745
717
746
718
@ Override
0 commit comments