diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MetadataHelper.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MetadataHelper.cs index 782e14e4446c2..869c5ef3f1113 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MetadataHelper.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MetadataHelper.cs @@ -6,7 +6,7 @@ namespace System.Reflection.Emit { - // This static helper class adds common entities to a Metadata Builder. + // This static helper class adds common entities to a MetadataBuilder. internal static class MetadataHelper { internal static AssemblyReferenceHandle AddAssemblyReference(Assembly assembly, MetadataBuilder metadata) @@ -34,7 +34,7 @@ internal static TypeDefinitionHandle AddTypeDefinition(MetadataBuilder metadata, // Add type metadata return metadata.AddTypeDefinition( attributes: typeBuilder.Attributes, - (typeBuilder.Namespace == null) ? default : metadata.GetOrAddString(typeBuilder.Namespace), + @namespace: (typeBuilder.Namespace == null) ? default : metadata.GetOrAddString(typeBuilder.Namespace), name: metadata.GetOrAddString(typeBuilder.Name), baseType: baseType, fieldList: MetadataTokens.FieldDefinitionHandle(fieldToken), @@ -49,28 +49,30 @@ internal static TypeReferenceHandle AddTypeReference(MetadataBuilder metadata, T internal static TypeReferenceHandle AddTypeReference(MetadataBuilder metadata, AssemblyReferenceHandle parent, string name, string? nameSpace) { return metadata.AddTypeReference( - parent, - (nameSpace == null) ? default : metadata.GetOrAddString(nameSpace), - metadata.GetOrAddString(name) + resolutionScope: parent, + @namespace: (nameSpace == null) ? default : metadata.GetOrAddString(nameSpace), + name: metadata.GetOrAddString(name) ); } internal static MethodDefinitionHandle AddMethodDefinition(MetadataBuilder metadata, MethodBuilderImpl methodBuilder, BlobBuilder methodSignatureBlob) { return metadata.AddMethodDefinition( - methodBuilder.Attributes, - MethodImplAttributes.IL, - metadata.GetOrAddString(methodBuilder.Name), - metadata.GetOrAddBlob(methodSignatureBlob), - -1, // No body supported yet + attributes: methodBuilder.Attributes, + implAttributes: MethodImplAttributes.IL, + name: metadata.GetOrAddString(methodBuilder.Name), + signature: metadata.GetOrAddBlob(methodSignatureBlob), + bodyOffset: -1, // No body supported yet parameterList: MetadataTokens.ParameterHandle(1) ); } - internal static FieldDefinitionHandle AddFieldDefinition(MetadataBuilder metadata, FieldInfo field) + internal static FieldDefinitionHandle AddFieldDefinition(MetadataBuilder metadata, FieldInfo field, BlobBuilder fieldSignatureBlob) { - return metadata.AddFieldDefinition(field.Attributes, metadata.GetOrAddString(field.Name), - metadata.GetOrAddBlob(MetadataSignatureHelper.FieldSignatureEncoder(field.FieldType))); + return metadata.AddFieldDefinition( + attributes: field.Attributes, + name: metadata.GetOrAddString(field.Name), + signature: metadata.GetOrAddBlob(fieldSignatureBlob)); } } } diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs index 841377f596e8a..c63e4c26e5d47 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; namespace System.Reflection.Emit { @@ -22,7 +21,7 @@ internal MethodBuilderImpl(string name, MethodAttributes attributes, CallingConv Type[]? parameterTypes, ModuleBuilderImpl module, TypeBuilderImpl declaringType) { _module = module; - _returnType = returnType ?? _module.GetTypeFromCoreAssembly("System.Void"); ; + _returnType = returnType ?? _module.GetTypeFromCoreAssembly(CoreTypeId.Void); _name = name; _attributes = attributes; _callingConventions = callingConventions; diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs index 0ed48f0c1a050..07dde6a0746ee 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs @@ -13,12 +13,15 @@ internal sealed class ModuleBuilderImpl : ModuleBuilder { private readonly Assembly _coreAssembly; private readonly string _name; - private readonly Dictionary _coreTypes = new(); + private Type?[]? _coreTypes; private readonly Dictionary _assemblyRefStore = new(); private readonly Dictionary _typeRefStore = new(); private readonly List _typeDefStore = new(); private int _nextMethodDefRowId = 1; private int _nextFieldDefRowId = 1; + private bool _coreTypesFullPopulated; + private static readonly Type[] s_coreTypes = { typeof(void), typeof(object), typeof(bool), typeof(char), typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), + typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(string), typeof(nint), typeof(nuint) }; internal ModuleBuilderImpl(string name, Assembly coreAssembly) { @@ -26,20 +29,65 @@ internal ModuleBuilderImpl(string name, Assembly coreAssembly) _name = name; } - internal Type GetTypeFromCoreAssembly(string name) + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Types are preserved via s_coreTypes")] + internal Type GetTypeFromCoreAssembly(CoreTypeId typeId) { - Type? type; + if (_coreTypes == null) + { + // Use s_coreTypes directly for runtime reflection + if (_coreAssembly == typeof(object).Assembly) + { + _coreTypes = s_coreTypes; + _coreTypesFullPopulated = true; + } + else + { + _coreTypes = new Type[s_coreTypes.Length]; + } + } - // TODO: Use Enum as the key for perf - if (!_coreTypes.TryGetValue(name, out type)) + int index = (int)typeId; + return _coreTypes[index] ?? (_coreTypes[index] = _coreAssembly.GetType(s_coreTypes[index].FullName!, throwOnError: true)!); + } + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Types are preserved via s_coreTypes")] + internal CoreTypeId? GetTypeIdFromCoreTypes(Type type) + { + if (_coreTypes == null) { -#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code - type = _coreAssembly.GetType(name, throwOnError: true)!; -#pragma warning restore IL2026 - _coreTypes.Add(name, type); + // Use s_coreTypes directly for runtime reflection + if (_coreAssembly == typeof(object).Assembly) + { + _coreTypes = s_coreTypes; + _coreTypesFullPopulated = true; + } + else + { + _coreTypes = new Type[s_coreTypes.Length]; + } + } + + if (!_coreTypesFullPopulated) + { + for (int i = 0; i < _coreTypes.Length; i++) + { + if (_coreTypes[i] == null) + { + _coreTypes[i] = _coreAssembly.GetType(s_coreTypes[i].FullName!, throwOnError: false)!; + } + } + _coreTypesFullPopulated = true; + } + + for (int i = 0; i < _coreTypes.Length; i++) + { + if (_coreTypes[i] == type) + { + return (CoreTypeId)i; + } } - return type; + return null; } internal void AppendMetadata(MetadataBuilder metadata) @@ -82,7 +130,7 @@ internal void AppendMetadata(MetadataBuilder metadata) foreach (FieldBuilderImpl field in typeBuilder._fieldDefStore) { - MetadataHelper.AddFieldDefinition(metadata, field); + MetadataHelper.AddFieldDefinition(metadata, field, MetadataSignatureHelper.FieldSignatureEncoder(field.FieldType, this)); _nextFieldDefRowId++; } } diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs index a17a1a86f4600..ad950b15152ac 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -9,16 +10,16 @@ namespace System.Reflection.Emit // TODO: Only support simple signatures. More complex signatures will be added. internal static class MetadataSignatureHelper { - internal static BlobBuilder FieldSignatureEncoder(Type fieldType) + internal static BlobBuilder FieldSignatureEncoder(Type fieldType, ModuleBuilderImpl module) { BlobBuilder fieldSignature = new(); - WriteSignatureTypeForReflectionType(new BlobEncoder(fieldSignature).FieldSignature(), fieldType); + WriteSignatureTypeForReflectionType(new BlobEncoder(fieldSignature).FieldSignature(), fieldType, module); return fieldSignature; } - internal static BlobBuilder MethodSignatureEncoder(ModuleBuilderImpl _module, Type[]? parameters, Type? returnType, bool isInstance) + internal static BlobBuilder MethodSignatureEncoder(ModuleBuilderImpl module, Type[]? parameters, Type? returnType, bool isInstance) { // Encoding return type and parameters. BlobBuilder methodSignature = new(); @@ -30,9 +31,9 @@ internal static BlobBuilder MethodSignatureEncoder(ModuleBuilderImpl _module, Ty MethodSignature(isInstanceMethod: isInstance). Parameters((parameters == null) ? 0 : parameters.Length, out retEncoder, out parEncoder); - if (returnType != null && returnType != _module.GetTypeFromCoreAssembly("System.Void")) + if (returnType != null && returnType != module.GetTypeFromCoreAssembly(CoreTypeId.Void)) { - WriteSignatureTypeForReflectionType(retEncoder.Type(), returnType); + WriteSignatureTypeForReflectionType(retEncoder.Type(), returnType, module); } else // If null mark ReturnTypeEncoder as void { @@ -43,46 +44,92 @@ internal static BlobBuilder MethodSignatureEncoder(ModuleBuilderImpl _module, Ty { foreach (Type parameter in parameters) { - WriteSignatureTypeForReflectionType(parEncoder.AddParameter().Type(), parameter); + WriteSignatureTypeForReflectionType(parEncoder.AddParameter().Type(), parameter, module); } } return methodSignature; } - private static void WriteSignatureTypeForReflectionType(SignatureTypeEncoder signature, Type type) + private static void WriteSignatureTypeForReflectionType(SignatureTypeEncoder signature, Type type, ModuleBuilderImpl module) { - // We need to translate from Reflection.Type to SignatureTypeEncoder. Most common types for proof of concept. More types will be added. - // TODO: This switch should be done by comparing Type objects, without fetching FullName. - switch (type.FullName) + CoreTypeId? typeId = module.GetTypeIdFromCoreTypes(type); + + // We need to translate from Reflection.Type to SignatureTypeEncoder. + switch (typeId) { - case "System.Boolean": + case CoreTypeId.Boolean: signature.Boolean(); break; - case "System.Byte": + case CoreTypeId.Byte: signature.Byte(); break; - case "System.Char": + case CoreTypeId.SByte: + signature.SByte(); + break; + case CoreTypeId.Char: signature.Char(); break; - case "System.Double": - signature.Double(); + case CoreTypeId.Int16: + signature.Int16(); + break; + case CoreTypeId.UInt16: + signature.UInt16(); break; - case "System.Int32": + case CoreTypeId.Int32: signature.Int32(); break; - case "System.Int64": + case CoreTypeId.UInt32: + signature.UInt32(); + break; + case CoreTypeId.Int64: signature.Int64(); break; - case "System.Object": + case CoreTypeId.UInt64: + signature.UInt64(); + break; + case CoreTypeId.Single: + signature.Single(); + break; + case CoreTypeId.Double: + signature.Double(); + break; + case CoreTypeId.IntPtr: + signature.IntPtr(); + break; + case CoreTypeId.UIntPtr: + signature.UIntPtr(); + break; + case CoreTypeId.Object: signature.Object(); break; - case "System.String": + case CoreTypeId.String: signature.String(); break; - - default: throw new NotSupportedException(SR.Format(SR.NotSupported_Signature, type.FullName)); + default: + throw new NotSupportedException(SR.Format(SR.NotSupported_Signature, type.FullName)); } } } + + internal enum CoreTypeId + { + Void, + Object, + Boolean, + Char, + SByte, + Byte, + Int16, + UInt16, + Int32, + UInt32, + Int64, + UInt64, + Single, + Double, + String, + IntPtr, + UIntPtr, + } } diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs index e640c86790333..71548abab22ef 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs @@ -71,7 +71,9 @@ protected override MethodBuilder DefineMethodCore(string name, MethodAttributes protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) => throw new NotImplementedException(); protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) => throw new NotImplementedException(); - protected override void SetParentCore([DynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)(-1))] Type? parent) + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2074:DynamicallyAccessedMembers", + Justification = "TODO: Need to figure out how to preserve System.Object public constructor")] + protected override void SetParentCore([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent) { if (parent != null) { @@ -86,9 +88,7 @@ protected override void SetParentCore([DynamicallyAccessedMembers((DynamicallyAc { if ((_attributes & TypeAttributes.Interface) != TypeAttributes.Interface) { -#pragma warning disable IL2074 // Value stored in field does not satisfy 'DynamicallyAccessedMembersAttribute' requirements. The return value of the source method does not have matching annotations. - _typeParent = _module.GetTypeFromCoreAssembly("System.Object"); -#pragma warning restore IL2074 + _typeParent = _module.GetTypeFromCoreAssembly(CoreTypeId.Object); } else { diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTestsWithVariousTypes.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTestsWithVariousTypes.cs index 0cff8c2327224..c459a9be15a56 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTestsWithVariousTypes.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTestsWithVariousTypes.cs @@ -63,7 +63,7 @@ public static IEnumerable VariousInterfacesStructsTestData() yield return new object[] { new Type[] { typeof(EmptyStruct) } }; yield return new object[] { new Type[] { typeof(StructWithField) } }; yield return new object[] { new Type[] { typeof(StructWithField), typeof(EmptyStruct) } }; - yield return new object[] { new Type[] { typeof(IMultipleMethod), typeof(EmptyStruct) , typeof(INoMethod2), typeof(StructWithField) } }; + yield return new object[] { new Type[] { typeof(IMultipleMethod), typeof(EmptyStruct), typeof(INoMethod2), typeof(StructWithField) } }; } [Theory]