IL: cache the ILTypeRef of a type def - #20259
Conversation
seekReadTypeDefAsTypeRef had no cache, so every reference to a type def re-read its row, rebuilt its name, walked the whole enclosing chain if nested, and allocated a fresh ILTypeRef. Nothing upstream absorbed that: seekReadTypeDefAsType is gated on reduceMemoryUsage and so is disabled in every long-running host. 30% of the calls to readBlobHeapAsTypeName came through this path on a 57-file project with 489 references. Retained memory after ParseAndCheckProject drops 2.08 MB there and 1.88 MB on the compiler's own project. Not gated on reduceMemoryUsage, like cacheTypeRef and cacheStringHeap: the cache lowers retained memory rather than trading memory for speed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
❗ Release notes requiredYou can open this PR in browser to add release notes: open in github.dev Caution No release notes found for the changed paths (see table below). Please make sure to add an entry with an informative description of the change as well as link to this pull request, issue and language suggestion if applicable. Release notes for this repository are based on Keep A Changelog format. The following format is recommended for this repository: `* . (PR #XXXXX)`
If you believe that release notes are not necessary for this PR, please add NO_RELEASE_NOTES label to the pull request.
|
T-Gro
left a comment
There was a problem hiding this comment.
Verified locally: the cache is keyed on the TypeDef row index and the result depends only on that immutable row (name, namespace, and the enclosing chain, which itself now routes back through the cache for nested types), so this is safe to memoize. Leaving it ungated on reduceMemoryUsage matches cacheTypeRef — the ILTypeRef is retained by the returned structures regardless, so deduping lowers retained memory rather than trading it for speed. All call sites go through the wrapper, and ./Build.cmd -c Debug is clean (0 warnings).
One optional nit: the initial capacity is 0, whereas the sibling caches seed it (getNumRows TableNames.TypeDef / 20 + 1). A hint would save a few rehashes on the hot path, but it's immaterial to correctness.
LGTM.
seekReadTypeDefAsTypeRefhas no cache. Every call re-reads the TypeDef row, rebuilds the type name,walks the entire enclosing chain for a nested type, and allocates a fresh
ILTypeRef.Attributing calls to
readBlobHeapAsTypeNameon a 57-file project with 489 references, 28,073 of 92,665came through this path — 30%, second only to type-def realisation itself.
This routes it through a per-reader cache keyed on the TypeDef row index, like the adjacent
cacheTypeRef. The result depends only on that row, all of it immutable metadata.