This PR re-works how we collect all method implementations, used e.g. for building vtables and for method-override-notifications. We had two performance problems in the static analysis:
AnalysisUniverse.collectMethodImplementations was an expensive serial operation, running every time after analysis has reached a fixed point.
AnalysisMethod.processMethodOverrides needed to check all methods for possible override-notifications (even though only few methods actually have a notification handler registered). It called AnalysisType.findMethod, which iterated through all declared methods to find a match.
I concluded that it is too difficult to maintain the complete and correct set of all reachable method overrides during the parallel analysis. When a method becomes reachable, it is too expensive to find all other methods that it possibly overrides. Therefore, the new approach now collects all possible implementations (even not reachable methods) whenever a new type becomes reachable or a new method is created. The correctly filtered list of all reachable implementations is produced on demand.
This means method override notifications can no longer be called during the parallel analysis. This is now done every time the analysis reaches a fixed point. In case that there are new notifications, the tasks are scheduled and the parallel analysis is restarted. While this is not ideal, I do not see a better way of handling this. It is certainly faster than before, because there are only few method override notifications registered.
In addition, this PR fixes a few other performance problems I spotted while looking at profiles, e.g., when we had de-generated hash maps due to bad hash code implementations; or where we need to cache frequently accessed information.
This PR re-works how we collect all method implementations, used e.g. for building vtables and for method-override-notifications. We had two performance problems in the static analysis:
AnalysisUniverse.collectMethodImplementations
was an expensive serial operation, running every time after analysis has reached a fixed point.AnalysisMethod.processMethodOverrides
needed to check all methods for possible override-notifications (even though only few methods actually have a notification handler registered). It calledAnalysisType.findMethod
, which iterated through all declared methods to find a match.I concluded that it is too difficult to maintain the complete and correct set of all reachable method overrides during the parallel analysis. When a method becomes reachable, it is too expensive to find all other methods that it possibly overrides. Therefore, the new approach now collects all possible implementations (even not reachable methods) whenever a new type becomes reachable or a new method is created. The correctly filtered list of all reachable implementations is produced on demand.
This means method override notifications can no longer be called during the parallel analysis. This is now done every time the analysis reaches a fixed point. In case that there are new notifications, the tasks are scheduled and the parallel analysis is restarted. While this is not ideal, I do not see a better way of handling this. It is certainly faster than before, because there are only few method override notifications registered.
In addition, this PR fixes a few other performance problems I spotted while looking at profiles, e.g., when we had de-generated hash maps due to bad hash code implementations; or where we need to cache frequently accessed information.