Suppress linker warnings properly (#84272)
authorBuyaa Namnan <bunamnan@microsoft.com>
Tue, 4 Apr 2023 23:22:03 +0000 (16:22 -0700)
committerGitHub <noreply@github.com>
Tue, 4 Apr 2023 23:22:03 +0000 (16:22 -0700)
* Suppress linker warnings properly

* Update core assembly types handling

* Update src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs

---------

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MetadataHelper.cs
src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs
src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs
src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs
src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs
src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTestsWithVariousTypes.cs

index 782e14e..869c5ef 100644 (file)
@@ -6,7 +6,7 @@ using System.Reflection.Metadata.Ecma335;
 
 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 @@ namespace System.Reflection.Emit
             // 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 @@ namespace System.Reflection.Emit
         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));
         }
     }
 }
index 841377f..c63e4c2 100644 (file)
@@ -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 @@ namespace System.Reflection.Emit
             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;
index 0ed48f0..07dde6a 100644 (file)
@@ -13,12 +13,15 @@ namespace System.Reflection.Emit
     {
         private readonly Assembly _coreAssembly;
         private readonly string _name;
-        private readonly Dictionary<string, Type> _coreTypes = new();
+        private Type?[]? _coreTypes;
         private readonly Dictionary<Assembly, AssemblyReferenceHandle> _assemblyRefStore = new();
         private readonly Dictionary<Type, TypeReferenceHandle> _typeRefStore = new();
         private readonly List<TypeBuilderImpl> _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 @@ namespace System.Reflection.Emit
             _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 @@ namespace System.Reflection.Emit
 
                 foreach (FieldBuilderImpl field in typeBuilder._fieldDefStore)
                 {
-                    MetadataHelper.AddFieldDefinition(metadata, field);
+                    MetadataHelper.AddFieldDefinition(metadata, field, MetadataSignatureHelper.FieldSignatureEncoder(field.FieldType, this));
                     _nextFieldDefRowId++;
                 }
             }
index a17a1a8..ad950b1 100644 (file)
@@ -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 @@ namespace System.Reflection.Emit
                 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 @@ namespace System.Reflection.Emit
             {
                 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,
+    }
 }
index e640c86..71548ab 100644 (file)
@@ -71,7 +71,9 @@ namespace System.Reflection.Emit
         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 @@ namespace System.Reflection.Emit
             {
                 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
                 {
index 0cff8c2..c459a9b 100644 (file)
@@ -63,7 +63,7 @@ namespace System.Reflection.Emit.Tests
             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]