Skip to content

Commit

Permalink
Suppress linker warnings properly (#84272)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
buyaa-n and jkotas authored Apr 4, 2023
1 parent f2d5967 commit 3e6ad47
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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),
Expand All @@ -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));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;

namespace System.Reflection.Emit
{
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,81 @@ internal sealed class ModuleBuilderImpl : ModuleBuilder
{
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)
{
_coreAssembly = 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)
Expand Down Expand Up @@ -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++;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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();
Expand All @@ -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
{
Expand All @@ -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,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public static IEnumerable<object[]> 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]
Expand Down

0 comments on commit 3e6ad47

Please sign in to comment.