3
3
4
4
using System . Collections . Concurrent ;
5
5
using System . Collections . ObjectModel ;
6
- using System . IO . MemoryMappedFiles ;
7
- using System . Reflection . PortableExecutable ;
8
6
9
7
namespace Microsoft . Windows . CsWin32 ;
10
8
@@ -25,19 +23,7 @@ internal class MetadataIndex
25
23
{
26
24
private static readonly int MaxPooledObjectCount = Math . Max ( Environment . ProcessorCount , 4 ) ;
27
25
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 ;
41
27
42
28
private readonly Platform ? platform ;
43
29
@@ -72,14 +58,14 @@ internal class MetadataIndex
72
58
/// <summary>
73
59
/// Initializes a new instance of the <see cref="MetadataIndex"/> class.
74
60
/// </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>
76
62
/// <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 )
78
64
{
79
- this . metadataPath = metadataPath ;
65
+ this . metadataFile = metadataFile ;
80
66
this . platform = platform ;
81
67
82
- using Rental < MetadataReader > mrRental = GetMetadataReader ( metadataPath ) ;
68
+ using MetadataFile . Rental mrRental = metadataFile . GetMetadataReader ( ) ;
83
69
MetadataReader mr = mrRental . Value ;
84
70
this . MetadataName = Path . GetFileNameWithoutExtension ( mr . GetString ( mr . GetAssemblyDefinition ( ) . Name ) ) ;
85
71
@@ -246,50 +232,7 @@ void PopulateNamespace(NamespaceDefinition ns, string? parentNamespace)
246
232
247
233
internal string CommonNamespaceDot { get ; }
248
234
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 } )";
293
236
294
237
/// <summary>
295
238
/// Attempts to translate a <see cref="TypeReferenceHandle"/> to a <see cref="TypeDefinitionHandle"/>.
@@ -423,21 +366,6 @@ internal bool TryGetEnumName(MetadataReader reader, string enumValueName, [NotNu
423
366
return false ;
424
367
}
425
368
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
-
441
369
private static string CommonPrefix ( IReadOnlyList < string > ss )
442
370
{
443
371
if ( ss . Count == 0 )
@@ -497,33 +425,4 @@ private static string CommonPrefix(IReadOnlyList<string> ss)
497
425
// Return null if the value was determined to be missing.
498
426
return this . enumTypeReference . HasValue && ! this . enumTypeReference . Value . IsNil ? this . enumTypeReference . Value : null ;
499
427
}
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
- }
529
428
}
0 commit comments