File: System\Reflection\TypeLoading\Modules\Ecma\EcmaModule.cs
Web Access
Project: src\src\libraries\System.Reflection.MetadataLoadContext\src\System.Reflection.MetadataLoadContext.csproj (System.Reflection.MetadataLoadContext)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
 
namespace System.Reflection.TypeLoading.Ecma
{
    /// <summary>
    /// Base class for all Module objects created by a MetadataLoadContext and get its metadata from a PEReader.
    /// </summary>
    internal sealed partial class EcmaModule : RoModule
    {
        private const int ModuleTypeToken = 0x02000001;
 
        private readonly EcmaAssembly _assembly;
        private readonly GuardedPEReader _guardedPEReader;
 
        //
        // "fullyQualifiedName" determines the string returned by Module.FullyQualifiedName. It is typically set to the full path of the
        // file on disk containing the module.
        //
        internal EcmaModule(EcmaAssembly assembly, string fullyQualifiedName, PEReader peReader, MetadataReader reader)
            : base(fullyQualifiedName)
        {
            Debug.Assert(assembly != null);
            Debug.Assert(fullyQualifiedName != null);
            Debug.Assert(peReader != null);
            Debug.Assert(reader != null);
 
            _assembly = assembly;
            _guardedPEReader = new GuardedPEReader(assembly.Loader, peReader, reader);
            _neverAccessThisExceptThroughModuleDefinitionProperty = reader.GetModuleDefinition();
        }
 
        internal sealed override RoAssembly GetRoAssembly() => _assembly;
        internal EcmaAssembly GetEcmaAssembly() => _assembly;
 
        public sealed override bool IsResource() => false;
        public sealed override int MDStreamVersion => throw new NotSupportedException(SR.NotSupported_MDStreamVersion);
        public sealed override int MetadataToken => 0x00000001; // The Module Table is exactly 1 record long so the token is always mdtModule | 0x000001
        public sealed override Guid ModuleVersionId => ModuleDefinition.Mvid.GetGuid(Reader);
        public sealed override string ScopeName => ModuleDefinition.Name.GetString(Reader);
 
        public sealed override IEnumerable<CustomAttributeData> CustomAttributes => ModuleDefinition.GetCustomAttributes().ToTrueCustomAttributes(this);
 
        internal MethodInfo? ComputeEntryPoint(bool fileRefEntryPointAllowed)
        {
            PEHeaders peHeaders = PEReader.PEHeaders;
            CorHeader corHeader = peHeaders.CorHeader!;
 
            if ((corHeader.Flags & CorFlags.NativeEntryPoint) != 0)
                return null;
 
            int entryPointToken = corHeader.EntryPointTokenOrRelativeVirtualAddress;
            Handle handle = entryPointToken.ToHandle();
            if (handle.IsNil)
                return null;
 
            HandleKind kind = handle.Kind;
            switch (kind)
            {
                case HandleKind.MethodDefinition:
                    {
                        MethodDefinitionHandle mdh = (MethodDefinitionHandle)handle;
                        return mdh.ResolveMethod<MethodInfo>(this, default);
                    }
 
                case HandleKind.AssemblyFile:
                    {
                        if (!fileRefEntryPointAllowed)
                            throw new BadImageFormatException();
 
                        MetadataReader reader = Reader;
                        string moduleName = ((AssemblyFileHandle)handle).GetAssemblyFile(reader).Name.GetString(reader);
                        EcmaModule? roModule = (EcmaModule?)(Assembly.GetModule(moduleName));
                        return roModule!.ComputeEntryPoint(fileRefEntryPointAllowed: false);
                    }
 
                default:
                    throw new BadImageFormatException();
            }
        }
 
        public sealed override void GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine)
        {
            PEHeaders peHeaders = PEReader.PEHeaders;
            PEMagic peMagic = peHeaders.PEHeader!.Magic;
            Machine coffMachine = peHeaders.CoffHeader.Machine;
            CorFlags corFlags = peHeaders.CorHeader!.Flags;
 
            peKind = default;
            if ((corFlags & CorFlags.ILOnly) != 0)
                peKind |= PortableExecutableKinds.ILOnly;
 
            if ((corFlags & CorFlags.Prefers32Bit) != 0)
                peKind |= PortableExecutableKinds.Preferred32Bit;
            else if ((corFlags & CorFlags.Requires32Bit) != 0)
                peKind |= PortableExecutableKinds.Required32Bit;
 
            if (peMagic == PEMagic.PE32Plus)
                peKind |= PortableExecutableKinds.PE32Plus;
 
            machine = (ImageFileMachine)coffMachine;
        }
 
        //
        // Search for members on <Module> type.
        //
        public sealed override FieldInfo? GetField(string name, BindingFlags bindingAttr) => GetModuleType().GetField(name, bindingAttr);
        public sealed override FieldInfo[] GetFields(BindingFlags bindingFlags) => GetModuleType().GetFields(bindingFlags);
        public sealed override MethodInfo[] GetMethods(BindingFlags bindingFlags) => GetModuleType().GetMethods(bindingFlags);
        protected sealed override MethodInfo? GetMethodImpl(string name, BindingFlags bindingAttr, Binder? binder, CallingConventions callConvention, Type[]? types, ParameterModifier[]? modifiers) => GetModuleType().InternalGetMethodImpl(name, bindingAttr, binder, callConvention, types, modifiers);
        private EcmaDefinitionType GetModuleType() => ModuleTypeToken.ToTypeDefinitionHandle().ResolveTypeDef(this);
 
        public sealed override Type[] GetTypes()
        {
            // Note: we don't expect this process to generate any loader exceptions so no need to implement the ReflectionTypeLoadException
            // logic.
 
            EnsureTypeDefTableFullyFilled();
            return TypeDefTable.ToArray<Type>(skip: 1); // 0x02000001 is the <Module> type which is always skipped by this api.
        }
 
        internal sealed override IEnumerable<RoType>? GetDefinedRoTypes()
        {
            EnsureTypeDefTableFullyFilled();
            return TypeDefTable.EnumerateValues(skip: 1)!; // 0x02000001 is the <Module> type which is always skipped by this api.
        }
 
        internal PEReader PEReader => _guardedPEReader.PEReader;
        internal MetadataReader Reader => _guardedPEReader.Reader;
 
        private ref readonly ModuleDefinition ModuleDefinition { get { Loader.DisposeCheck(); return ref _neverAccessThisExceptThroughModuleDefinitionProperty; } }
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]  // Block from debugger watch windows so they don't AV the debugged process.
        private readonly ModuleDefinition _neverAccessThisExceptThroughModuleDefinitionProperty;
    }
}