Example #1
0
        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));
        }
Example #2
0
        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
                       ));
        }
Example #3
0
        /// <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));
        }
Example #4
0
        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));
        }