Skip to content

Commit de7b4c5

Browse files
Simplify further
1 parent 9fec72c commit de7b4c5

1 file changed

Lines changed: 56 additions & 40 deletions

File tree

src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.SkeletonReferenceCache.cs

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,17 @@ private sealed class SkeletonReferenceSet
251251
/// </summary>
252252
private readonly DeferredDocumentationProvider _documentationProvider;
253253

254+
/// <summary>
255+
/// The actual assembly metadata produced from the data pointed to in <see cref="_storage"/>.
256+
/// </summary>
257+
private readonly AsyncLazy<AssemblyMetadata?> _metadata;
258+
259+
/// <summary>
260+
/// Mapping from different values of <see cref="MetadataReferenceProperties"/> to the actual <see
261+
/// cref="MetadataReference"/> produced for it. Used so that if the same compilation is referenced from
262+
/// different projects with/without the same properties that the right references are handed out (and shared
263+
/// if possible).
264+
/// </summary>
254265
/// <remarks>
255266
/// This instance should be locked when being read/written.
256267
/// </remarks>
@@ -264,58 +275,34 @@ public SkeletonReferenceSet(
264275
_storage = storage;
265276
_assemblyName = assemblyName;
266277
_documentationProvider = documentationProvider;
267-
}
268-
269-
public MetadataReference? TryGetAlreadyBuiltMetadataReference(MetadataReferenceProperties properties)
270-
{
271-
// lookup first and eagerly return cached value if we have it.
272-
lock (_metadataReferences)
273-
return _metadataReferences.TryGetValue(properties, out var lazy) && lazy.TryGetValue(out var result) ? result : null;
274-
}
275-
276-
public Task<MetadataReference?> GetMetadataReferenceAsync(MetadataReferenceProperties properties, CancellationToken cancellationToken)
277-
{
278-
AsyncLazy<MetadataReference?>? lazy;
279-
lock (_metadataReferences)
280-
{
281-
if (!_metadataReferences.TryGetValue(properties, out lazy))
282-
{
283-
// note: computing the reference is actually synchronous. However, this ensures we don't have N
284-
// threads blocking on a lazy to compute the work. Instead, we'll only occupy one thread, while
285-
// any concurrent requests asynchronously wait for that work to be one.
286-
lazy = new AsyncLazy<MetadataReference?>(c => ComputeReferenceAsync(properties, c), cacheResult: true);
287-
_metadataReferences.Add(properties, lazy);
288-
}
289-
}
290278

291-
return lazy.GetValueAsync(cancellationToken);
292-
293-
Task<MetadataReference?> ComputeReferenceAsync(MetadataReferenceProperties properties, CancellationToken cancellationToken)
294-
{
295-
return Task.FromResult(CreateReference(properties.Aliases, properties.EmbedInteropTypes, _documentationProvider));
296-
}
279+
// note: computing the assembly metadata is actually synchronous. However, this ensures we don't have N
280+
// threads blocking on a lazy to compute the work. Instead, we'll only occupy one thread, while any
281+
// concurrent requests asynchronously wait for that work to be one.
282+
_metadata = new AsyncLazy<AssemblyMetadata?>(c => Task.FromResult(ComputeMetadata(_storage, c)), cacheResult: true);
297283
}
298284

299-
private MetadataReference? CreateReference(ImmutableArray<string> aliases, bool embedInteropTypes, DocumentationProvider documentationProvider)
285+
private static AssemblyMetadata? ComputeMetadata(ITemporaryStreamStorage? storage, CancellationToken cancellationToken)
300286
{
301-
if (_storage == null)
287+
if (storage == null)
302288
return null;
303289

304290
// first see whether we can use native memory directly.
305-
var stream = _storage.ReadStream();
306-
AssemblyMetadata metadata;
291+
var stream = storage.ReadStream(cancellationToken);
307292

308293
if (stream is ISupportDirectMemoryAccess supportNativeMemory)
309294
{
310295
// this is unfortunate that if we give stream, compiler will just re-copy whole content to
311296
// native memory again. this is a way to get around the issue by we getting native memory ourselves and then
312297
// give them pointer to the native memory. also we need to handle lifetime ourselves.
313-
metadata = AssemblyMetadata.Create(ModuleMetadata.CreateFromImage(supportNativeMemory.GetPointer(), (int)stream.Length));
298+
var metadata = AssemblyMetadata.Create(ModuleMetadata.CreateFromImage(supportNativeMemory.GetPointer(), (int)stream.Length));
314299

315300
// Tie lifetime of stream to metadata we created. It is important to tie this to the Metadata and not the
316301
// metadata reference, as PE symbols hold onto just the Metadata. We can use Add here since we created
317302
// a brand new object in AssemblyMetadata.Create above.
318303
s_lifetime.Add(metadata, supportNativeMemory);
304+
305+
return metadata;
319306
}
320307
else
321308
{
@@ -325,14 +312,43 @@ public SkeletonReferenceSet(
325312

326313
// We don't deterministically release the resulting metadata since we don't know
327314
// when we should. So we leave it up to the GC to collect it and release all the associated resources.
328-
metadata = AssemblyMetadata.CreateFromStream(stream);
315+
return AssemblyMetadata.CreateFromStream(stream, leaveOpen: false);
316+
}
317+
}
318+
319+
public MetadataReference? TryGetAlreadyBuiltMetadataReference(MetadataReferenceProperties properties)
320+
{
321+
// lookup first and eagerly return cached value if we have it.
322+
lock (_metadataReferences)
323+
return _metadataReferences.TryGetValue(properties, out var lazy) && lazy.TryGetValue(out var result) ? result : null;
324+
}
325+
326+
public Task<MetadataReference?> GetMetadataReferenceAsync(MetadataReferenceProperties properties, CancellationToken cancellationToken)
327+
{
328+
AsyncLazy<MetadataReference?>? lazy;
329+
lock (_metadataReferences)
330+
{
331+
if (!_metadataReferences.TryGetValue(properties, out lazy))
332+
{
333+
lazy = new AsyncLazy<MetadataReference?>(c => ComputeReferenceAsync(properties, c), cacheResult: true);
334+
_metadataReferences.Add(properties, lazy);
335+
}
329336
}
330337

331-
return metadata.GetReference(
332-
documentation: documentationProvider,
333-
aliases: aliases,
334-
embedInteropTypes: embedInteropTypes,
335-
display: _assemblyName);
338+
return lazy.GetValueAsync(cancellationToken);
339+
340+
async Task<MetadataReference?> ComputeReferenceAsync(MetadataReferenceProperties properties, CancellationToken cancellationToken)
341+
{
342+
var metadata = await _metadata.GetValueAsync(cancellationToken).ConfigureAwait(false);
343+
if (metadata == null)
344+
return null;
345+
346+
return metadata.GetReference(
347+
documentation: _documentationProvider,
348+
aliases: properties.Aliases,
349+
embedInteropTypes: properties.EmbedInteropTypes,
350+
display: _assemblyName);
351+
}
336352
}
337353
}
338354
}

0 commit comments

Comments
 (0)