33
44using  System . Collections . Concurrent ; 
55using  System . Collections . ObjectModel ; 
6- using  System . IO . MemoryMappedFiles ; 
7- using  System . Reflection . PortableExecutable ; 
86
97namespace  Microsoft . Windows . CsWin32 ; 
108
@@ -25,19 +23,7 @@ internal class MetadataIndex
2523{ 
2624    private  static readonly  int  MaxPooledObjectCount  =  Math . Max ( Environment . ProcessorCount ,  4 ) ; 
2725
28-     private  static readonly  Action < MetadataReader ,  object ? >  ReaderRecycleDelegate  =  Recycle ; 
29- 
30-     private  static readonly  Dictionary < CacheKey ,  MetadataIndex >  Cache  =  new ( ) ; 
31- 
32-     /// <summary> 
33-     /// A cache of metadata files read. 
34-     /// All access to this should be within a <see cref="Cache"/> lock. 
35-     /// </summary> 
36-     private  static readonly  Dictionary < string ,  MemoryMappedFile >  MetadataFiles  =  new ( StringComparer . OrdinalIgnoreCase ) ; 
37- 
38-     private  static readonly  ConcurrentDictionary < string ,  ConcurrentBag < ( PEReader ,  MetadataReader ) > >  PooledPEReaders  =  new ( StringComparer . OrdinalIgnoreCase ) ; 
39- 
40-     private  readonly  string  metadataPath ; 
26+     private  readonly  MetadataFile  metadataFile ; 
4127
4228    private  readonly  Platform ?  platform ; 
4329
@@ -72,14 +58,14 @@ internal class MetadataIndex
7258    /// <summary> 
7359    /// Initializes a new instance of the <see cref="MetadataIndex"/> class. 
7460    /// </summary> 
75-     /// <param name="metadataPath ">The path to the  metadata that this index will represent.</param> 
61+     /// <param name="metadataFile ">The metadata file  that this index will represent.</param> 
7662    /// <param name="platform">The platform filter to apply when reading the metadata.</param> 
77-     private  MetadataIndex ( string   metadataPath ,  Platform ?  platform ) 
63+     internal  MetadataIndex ( MetadataFile   metadataFile ,  Platform ?  platform ) 
7864    { 
79-         this . metadataPath  =  metadataPath ; 
65+         this . metadataFile  =  metadataFile ; 
8066        this . platform  =  platform ; 
8167
82-         using  Rental < MetadataReader >  mrRental  =  GetMetadataReader ( metadataPath ) ; 
68+         using  MetadataFile . Rental  mrRental  =  metadataFile . GetMetadataReader ( ) ; 
8369        MetadataReader  mr  =  mrRental . Value ; 
8470        this . MetadataName  =  Path . GetFileNameWithoutExtension ( mr . GetString ( mr . GetAssemblyDefinition ( ) . Name ) ) ; 
8571
@@ -246,50 +232,7 @@ void PopulateNamespace(NamespaceDefinition ns, string? parentNamespace)
246232
247233    internal  string  CommonNamespaceDot  {  get ;  } 
248234
249-     private  string  DebuggerDisplay  =>  $ "{ this . metadataPath }  ({ this . platform } )"; 
250- 
251-     internal  static MetadataIndex  Get ( string  metadataPath ,  Platform ?  platform ) 
252-     { 
253-         metadataPath  =  Path . GetFullPath ( metadataPath ) ; 
254-         CacheKey  key  =  new ( metadataPath ,  platform ) ; 
255-         lock  ( Cache ) 
256-         { 
257-             if  ( ! Cache . TryGetValue ( key ,  out  MetadataIndex  index ) ) 
258-             { 
259-                 Cache . Add ( key ,  index  =  new  MetadataIndex ( metadataPath ,  platform ) ) ; 
260-             } 
261- 
262-             return  index ; 
263-         } 
264-     } 
265- 
266-     internal  static Rental < MetadataReader >  GetMetadataReader ( string  metadataPath ) 
267-     { 
268-         if  ( PooledPEReaders . TryGetValue ( metadataPath ,  out  ConcurrentBag < ( PEReader ,  MetadataReader ) > ?  pool )  &&  pool . TryTake ( out  ( PEReader ,  MetadataReader )  readers ) ) 
269-         { 
270-             return  new ( readers . Item2 ,  ReaderRecycleDelegate ,  ( readers . Item1 ,  metadataPath ) ) ; 
271-         } 
272- 
273-         PEReader  peReader  =  new  PEReader ( CreateFileView ( metadataPath ) ) ; 
274-         return  new ( peReader . GetMetadataReader ( ) ,  ReaderRecycleDelegate ,  ( peReader ,  metadataPath ) ) ; 
275-     } 
276- 
277-     internal  static MemoryMappedViewStream  CreateFileView ( string  metadataPath ) 
278-     { 
279-         lock  ( Cache ) 
280-         { 
281-             // We use a memory mapped file so that many threads can perform random access on it concurrently, 
282-             // only mapping the file into memory once. 
283-             if  ( ! MetadataFiles . TryGetValue ( metadataPath ,  out  MemoryMappedFile ?  file ) ) 
284-             { 
285-                 var  metadataStream  =  new  FileStream ( metadataPath ,  FileMode . Open ,  FileAccess . Read ,  FileShare . Read ) ; 
286-                 file  =  MemoryMappedFile . CreateFromFile ( metadataStream ,  mapName :  null ,  capacity :  0 ,  MemoryMappedFileAccess . Read ,  HandleInheritability . None ,  leaveOpen :  false ) ; 
287-                 MetadataFiles . Add ( metadataPath ,  file ) ; 
288-             } 
289- 
290-             return  file . CreateViewStream ( offset :  0 ,  size :  0 ,  MemoryMappedFileAccess . Read ) ; 
291-         } 
292-     } 
235+     private  string  DebuggerDisplay  =>  $ "{ this . metadataFile . Path }  ({ this . platform } )"; 
293236
294237    /// <summary> 
295238    /// Attempts to translate a <see cref="TypeReferenceHandle"/> to a <see cref="TypeDefinitionHandle"/>. 
@@ -423,21 +366,6 @@ internal bool TryGetEnumName(MetadataReader reader, string enumValueName, [NotNu
423366        return  false ; 
424367    } 
425368
426-     private  static void  Recycle ( MetadataReader  metadataReader ,  object ?  state ) 
427-     { 
428-         ( PEReader  peReader ,  string  metadataPath )  =  ( ( PEReader ,  string ) ) state ! ; 
429-         ConcurrentBag < ( PEReader ,  MetadataReader ) >  pool  =  PooledPEReaders . GetOrAdd ( metadataPath ,  _ =>  new ( ) ) ; 
430-         if  ( pool . Count  <  MaxPooledObjectCount ) 
431-         { 
432-             pool . Add ( ( peReader ,  metadataReader ) ) ; 
433-         } 
434-         else 
435-         { 
436-             // The pool is full. Dispose of this rather than recycle it. 
437-             peReader . Dispose ( ) ; 
438-         } 
439-     } 
440- 
441369    private  static string  CommonPrefix ( IReadOnlyList < string >  ss ) 
442370    { 
443371        if  ( ss . Count  ==  0 ) 
@@ -497,33 +425,4 @@ private static string CommonPrefix(IReadOnlyList<string> ss)
497425        // Return null if the value was determined to be missing. 
498426        return  this . enumTypeReference . HasValue  &&  ! this . enumTypeReference . Value . IsNil  ?  this . enumTypeReference . Value  :  null ; 
499427    } 
500- 
501-     [ DebuggerDisplay ( "{"  +  nameof ( DebuggerDisplay )  +  ",nq}" ) ] 
502-     private  struct  CacheKey  :  IEquatable < CacheKey > 
503-     { 
504-         internal  CacheKey ( string  metadataPath ,  Platform ?  platform ) 
505-         { 
506-             this . MetadataPath  =  metadataPath ; 
507-             this . Platform  =  platform ; 
508-         } 
509- 
510-         internal  string  MetadataPath  {  get ;  } 
511- 
512-         internal  Platform ?  Platform  {  get ;  } 
513- 
514-         private  string  DebuggerDisplay  =>  $ "{ this . MetadataPath }  ({ this . Platform } )"; 
515- 
516-         public  override  bool  Equals ( object  obj )  =>  obj  is  CacheKey  other  &&  this . Equals ( other ) ; 
517- 
518-         public  bool  Equals ( CacheKey  other ) 
519-         { 
520-             return  this . Platform  ==  other . Platform 
521-                 &&  string . Equals ( this . MetadataPath ,  other . MetadataPath ,  StringComparison . OrdinalIgnoreCase ) ; 
522-         } 
523- 
524-         public  override  int  GetHashCode ( ) 
525-         { 
526-             return  StringComparer . OrdinalIgnoreCase . GetHashCode ( this . MetadataPath )  +  ( this . Platform . HasValue  ?  ( int ) this . Platform . Value  :  0 ) ; 
527-         } 
528-     } 
529428} 
0 commit comments