internal static MetadataReference CreateFromAssemblyInternal( Assembly assembly, MetadataReferenceProperties properties, DocumentationProvider documentation = null) { // Note: returns MetadataReference and not PortableExecutableReference so that we can in future support assemblies that // which are not backed by PE image. if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); } if (assembly.IsDynamic) { throw new NotSupportedException(CodeAnalysisResources.CantCreateReferenceToDynamicAssembly); } if (properties.Kind != MetadataImageKind.Assembly) { throw new ArgumentException(CodeAnalysisResources.CantCreateModuleReferenceToAssembly, nameof(properties)); } string location = AssemblyLocationLightUp.GetAssemblyLocation(assembly); Stream peStream = FileUtilities.OpenFileStream(location); // The file is locked by the CLR assembly loader, so we can create a lazily read metadata, // which might also lock the file until the reference is GC'd. var metadata = AssemblyMetadata.CreateFromStream(peStream); return(metadata.GetReference(documentation, properties.Aliases, properties.EmbedInteropTypes, filePath: location)); }
internal static PortableExecutableReference CreateFromAssemblyInternal( Assembly assembly, MetadataReferenceProperties properties, DocumentationProvider?documentation = null ) { // Note: returns MetadataReference and not PortableExecutableReference so that we can in future support assemblies that // which are not backed by PE image. if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); } if (assembly.IsDynamic) { throw new NotSupportedException( CodeAnalysisResources.CantCreateReferenceToDynamicAssembly ); } if (properties.Kind != MetadataImageKind.Assembly) { throw new ArgumentException( CodeAnalysisResources.CantCreateModuleReferenceToAssembly, nameof(properties) ); } string location = assembly.Location; if (string.IsNullOrEmpty(location)) { throw new NotSupportedException( CodeAnalysisResources.CantCreateReferenceToAssemblyWithoutLocation ); } Stream peStream = StandardFileSystem.Instance.OpenFileWithNormalizedException( location, FileMode.Open, FileAccess.Read, FileShare.Read ); // The file is locked by the CLR assembly loader, so we can create a lazily read metadata, // which might also lock the file until the reference is GC'd. var metadata = AssemblyMetadata.CreateFromStream(peStream); return(new MetadataImageReference( metadata, properties, documentation, location, display: null )); }
/// <summary> /// Creates a reference to a single-module assembly or a stand-alone module from data in specified stream. /// Reads the content of the stream into memory and closes the stream upon return. /// </summary> /// <param name="peStream">Assembly image.</param> /// <param name="properties">Reference properties (extern aliases, type embedding, <see cref="MetadataImageKind"/>).</param> /// <param name="documentation">Provides XML documentation for symbol found in the reference.</param> /// <param name="filePath">Optional path that describes the location of the metadata. The file doesn't need to exist on disk. The path is opaque to the compiler.</param> /// <exception cref="ArgumentException"><paramref name="peStream"/> doesn't support read and seek operations.</exception> /// <exception cref="ArgumentNullException"><paramref name="peStream"/> is null.</exception> /// <exception cref="IOException">An error occurred while reading the stream.</exception> /// <remarks> /// Performance considerations: /// <para> /// It is recommended to use <see cref="AssemblyMetadata.CreateFromStream(Stream, PEStreamOptions)"/> or <see cref="ModuleMetadata.CreateFromStream(Stream, PEStreamOptions)"/> /// API when creating multiple references to the same metadata. /// Reusing <see cref="Metadata"/> object to create multiple references allows for sharing data across these references. /// </para> /// <para> /// The method eagerly reads the entire content of <paramref name="peStream"/> into native heap. The native memory block is released /// when the resulting reference becomes unreachable and GC collects it. To decrease memory footprint of the reference and/or manage /// the lifetime deterministically use <see cref="AssemblyMetadata.CreateFromStream(Stream, PEStreamOptions)"/> /// to create an <see cref="IDisposable"/> metadata object and /// <see cref="AssemblyMetadata.GetReference(DocumentationProvider, ImmutableArray{string}, bool, string, string)"/> /// to get a reference to it. /// </para> /// </remarks> public static PortableExecutableReference CreateFromStream( Stream peStream, MetadataReferenceProperties properties = default, DocumentationProvider?documentation = null, string?filePath = null) { // Prefetch data and close the stream. var metadata = AssemblyMetadata.CreateFromStream(peStream, PEStreamOptions.PrefetchEntireImage); return(new MetadataImageReference(metadata, properties, documentation, filePath, display: null)); }
public MetadataReference CreateReference(ImmutableArray <string> aliases, bool embedInteropTypes, DocumentationProvider documentationProvider) { if (this.IsEmpty) { return(null); } // first see whether we can use native memory directly. var stream = _storage.ReadStream(); var supportNativeMemory = stream as ISupportDirectMemoryAccess; if (supportNativeMemory != null) { // this is unfortunate that if we give stream, compiler will just re-copy whole content to // native memory again. this is a way to get around the issue by we getting native memory ourselves and then // give them pointer to the native memory. also we need to handle lifetime ourselves. var metadata = AssemblyMetadata.Create(ModuleMetadata.CreateFromImage(supportNativeMemory.GetPointer(), (int)stream.Length)); var referenceWithNativeMemory = metadata.GetReference( documentation: documentationProvider, aliases: aliases, embedInteropTypes: embedInteropTypes, display: _assemblyName); // tie lifetime of stream to metadata reference we created. native memory's lifetime is tied to // stream internally and stream is shared between same temporary storage. so here, we should be // sharing same native memory for all skeleton assemblies from same project snapshot. s_lifetime.GetValue(referenceWithNativeMemory, _ => stream); return(referenceWithNativeMemory); } // Otherwise, we just let it use stream. Unfortunately, if we give stream, compiler will // internally copy it to native memory again. since compiler owns lifetime of stream, // it would be great if compiler can be little bit smarter on how it deals with stream. // We don't deterministically release the resulting metadata since we don't know // when we should. So we leave it up to the GC to collect it and release all the associated resources. var metadataFromStream = AssemblyMetadata.CreateFromStream(stream); return(metadataFromStream.GetReference( documentation: documentationProvider, aliases: aliases, embedInteropTypes: embedInteropTypes, display: _assemblyName)); }
public MetadataReference CreateReference(ImmutableArray <string> aliases, bool embedInteropTypes, DocumentationProvider documentationProvider) { if (this.IsEmpty) { return(null); } // first see whether we can use native memory directly. var stream = _storage.ReadStream(); var supportNativeMemory = stream as ISupportDirectMemoryAccess; AssemblyMetadata metadata; if (supportNativeMemory != null) { // this is unfortunate that if we give stream, compiler will just re-copy whole content to // native memory again. this is a way to get around the issue by we getting native memory ourselves and then // give them pointer to the native memory. also we need to handle lifetime ourselves. metadata = AssemblyMetadata.Create(ModuleMetadata.CreateFromImage(supportNativeMemory.GetPointer(), (int)stream.Length)); // Tie lifetime of stream to metadata we created. It is important to tie this to the Metadata and not the // metadata reference, as PE symbols hold onto just the Metadata. We can use Add here since we created // a brand new object in AssemblyMetadata.Create above. s_lifetime.Add(metadata, supportNativeMemory); } else { // Otherwise, we just let it use stream. Unfortunately, if we give stream, compiler will // internally copy it to native memory again. since compiler owns lifetime of stream, // it would be great if compiler can be little bit smarter on how it deals with stream. // We don't deterministically release the resulting metadata since we don't know // when we should. So we leave it up to the GC to collect it and release all the associated resources. metadata = AssemblyMetadata.CreateFromStream(stream); } return(metadata.GetReference( documentation: documentationProvider, aliases: aliases, embedInteropTypes: embedInteropTypes, display: _assemblyName)); }