From 6bf03ba46e204ecb8dd0c23683037b18f231dfca Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Thu, 13 Aug 2026 15:35:32 +0200 Subject: [PATCH] IL: cache the ILTypeRef of a type def 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) --- src/Compiler/AbstractIL/ilread.fs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Compiler/AbstractIL/ilread.fs b/src/Compiler/AbstractIL/ilread.fs index 0ccdd9cf35c..4cacdafc9ed 100644 --- a/src/Compiler/AbstractIL/ilread.fs +++ b/src/Compiler/AbstractIL/ilread.fs @@ -1141,6 +1141,7 @@ type ILMetadataReader = seekReadMemberRefAsFieldSpec: MemberRefAsFspecIdx -> ILFieldSpec seekReadCustomAttr: CustomAttrIdx -> ILAttribute seekReadTypeRef: int -> ILTypeRef + seekReadTypeDefAsTypeRef: int -> ILTypeRef seekReadTypeRefAsType: TypeRefAsTypIdx -> ILType readBlobHeapAsPropertySig: BlobAsPropSigIdx -> ILThisConvention * ILType * ILTypes readBlobHeapAsFieldSig: BlobAsFieldSigIdx -> ILType @@ -2334,7 +2335,10 @@ and seekReadTypeDefAsTypeUncached ctxtH (TypeDefAsTypIdx(boxity, ginst, idx)) = let ctxt = getHole ctxtH mkILTy boxity (ILTypeSpec.Create(seekReadTypeDefAsTypeRef ctxt idx, ginst)) -and seekReadTypeDefAsTypeRef (ctxt: ILMetadataReader) idx = +and seekReadTypeDefAsTypeRef (ctxt: ILMetadataReader) idx = ctxt.seekReadTypeDefAsTypeRef idx + +and seekReadTypeDefAsTypeRefUncached ctxtH idx = + let (ctxt: ILMetadataReader) = getHole ctxtH let mdv = ctxt.mdfile.GetView() let enc = @@ -4504,6 +4508,9 @@ let openMetadataReader let cacheTypeDefAsType = mkCacheGeneric reduceMemoryUsage inbase "TypeDefAsType" (getNumRows TableNames.TypeDef / 20 + 1) + let cacheTypeDefAsTypeRef = + mkCacheGeneric false inbase "TypeDefAsTypeRef" 0 + let cacheMethodDefAsMethodData = mkCacheGeneric reduceMemoryUsage inbase "MethodDefAsMethodData" (getNumRows TableNames.Method / 20 + 1) @@ -4575,6 +4582,7 @@ let openMetadataReader seekReadMemberRefAsFieldSpec = seekReadMemberRefAsFieldSpecUncached ctxtH seekReadCustomAttr = cacheCustomAttr (seekReadCustomAttrUncached ctxtH) seekReadTypeRef = cacheTypeRef (seekReadTypeRefUncached ctxtH) + seekReadTypeDefAsTypeRef = cacheTypeDefAsTypeRef (seekReadTypeDefAsTypeRefUncached ctxtH) readBlobHeapAsPropertySig = cacheBlobHeapAsPropertySig (readBlobHeapAsPropertySigUncached ctxtH) readBlobHeapAsFieldSig = cacheBlobHeapAsFieldSig (readBlobHeapAsFieldSigUncached ctxtH) readBlobHeapAsMethodSig = cacheBlobHeapAsMethodSig (readBlobHeapAsMethodSigUncached ctxtH)