Conversation
|
@copilot Can you measure whether this has any performance benefit compared to CI running on master? |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR introduces caching and cheaper equality checks to reduce overhead from frequent annotation conversions in the Value Checker.
Changes:
- Replaces set-based annotation equality checks in
ValueVisitorwith hierarchy-annotation retrieval. - Adds an identity-based cache to avoid repeated non-special-case conversions in
ValueAnnotatedTypeFactory. - Refines widening logic to explicitly select the value-hierarchy annotation (and error if absent).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| framework/src/main/java/org/checkerframework/common/value/ValueVisitor.java | Avoids building AnnotationMirrorSet for integral cast safety checks by using hierarchy lookups. |
| framework/src/main/java/org/checkerframework/common/value/ValueAnnotatedTypeFactory.java | Adds an IdentityHashMap cache and adjusts conversion/widening logic to reduce repeated work. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (castAnnos.equals(exprAnnos)) { | ||
| AnnotationMirror castAnno = castType.getAnnotationInHierarchy(atypeFactory.UNKNOWNVAL); | ||
| AnnotationMirror exprAnno = exprType.getAnnotationInHierarchy(atypeFactory.UNKNOWNVAL); | ||
| if (castAnno == exprAnno) { |
There was a problem hiding this comment.
castAnno == exprAnno checks reference identity, not semantic equality. This is likely a behavioral regression from the prior AnnotationMirrorSet.equals(...) check: two equivalent AnnotationMirrors may be different instances, causing isTypeCastSafe to incorrectly return false and potentially emit spurious warnings. Use a semantic comparison (e.g., AnnotationUtils.areSame(castAnno, exprAnno) or an equivalent factory/hierarchy equality check) to preserve the prior behavior.
| if (castAnno == exprAnno) { | |
| if (AnnotationUtils.areSame(castAnno, exprAnno)) { |
| private final IdentityHashMap<AnnotationMirror, Boolean> specialIntRangeCache = | ||
| new IdentityHashMap<>(); |
There was a problem hiding this comment.
This cache is unbounded and holds strong references to AnnotationMirror keys, which can grow without limit during long compilations or across many compilation units and increase memory retention. Consider bounding the cache (e.g., size-limited LRU) and/or clearing it at a known lifecycle boundary for the factory to avoid memory growth; alternatively, redesign the cache key to avoid storing per-instance AnnotationMirror objects when only a few “special” cases exist.
| Boolean cached = specialIntRangeCache.get(anm); | ||
| if (Boolean.FALSE.equals(cached)) { | ||
| return anm; // fast path, ~95%+ of calls | ||
| } |
There was a problem hiding this comment.
Storing isSpecial=true entries doesn’t currently create a faster path (the method still computes annotationName(...) and re-checks all branches on every call), but it does increase cache size and memory retention. Either (a) only cache the non-special case (store false entries only), or (b) cache richer information (e.g., which special kind it is) so subsequent calls can skip annotationName(...) and branching while still handling differing max values.
| if (cached == null) { | ||
| specialIntRangeCache.put(anm, isSpecial); |
There was a problem hiding this comment.
Storing isSpecial=true entries doesn’t currently create a faster path (the method still computes annotationName(...) and re-checks all branches on every call), but it does increase cache size and memory retention. Either (a) only cache the non-special case (store false entries only), or (b) cache richer information (e.g., which special kind it is) so subsequent calls can skip annotationName(...) and branching while still handling differing max values.
| if (cached == null) { | |
| specialIntRangeCache.put(anm, isSpecial); | |
| if (cached == null && !isSpecial) { | |
| specialIntRangeCache.put(anm, false); |
I checked the CI data for this PR commit ( Current status: the PR CI run is still queued ( Master baseline from recent completed
So I can’t yet claim a measured performance benefit from CI timing until run 24699635200 completes. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
Maybe we should limit the size of the cache?