Skip to content

Commit a42a703

Browse files
authored
Support references to unmanaged function pointers in Reflection.Emit (#121128)
This fixes #120909.
1 parent 3eb06e5 commit a42a703

File tree

9 files changed

+81
-42
lines changed

9 files changed

+81
-42
lines changed

src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/FieldOnTypeBuilderInstantiation.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ internal FieldOnTypeBuilderInstantiation(FieldInfo field, TypeBuilderInstantiati
5656
#region Public Abstract\Virtual Members
5757
public override Type[] GetRequiredCustomModifiers() { return _field.GetRequiredCustomModifiers(); }
5858
public override Type[] GetOptionalCustomModifiers() { return _field.GetOptionalCustomModifiers(); }
59+
public override Type GetModifiedFieldType() => _field.GetModifiedFieldType();
5960
public override void SetValueDirect(TypedReference obj, object value)
6061
{
6162
throw new NotImplementedException();

src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/MethodOnTypeBuilderInstantiation.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public override MethodInfo MakeGenericMethod(params Type[] typeArgs)
118118

119119
#region Public Abstract\Virtual Members
120120
public override Type ReturnType => _method.ReturnType;
121-
public override ParameterInfo ReturnParameter => throw new NotSupportedException();
121+
public override ParameterInfo ReturnParameter => _method.ReturnParameter;
122122
public override ICustomAttributeProvider ReturnTypeCustomAttributes => throw new NotSupportedException();
123123
public override MethodInfo GetBaseDefinition() { throw new NotSupportedException(); }
124124
#endregion

src/libraries/System.Private.CoreLib/src/System/Reflection/ModifiedType.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,10 @@ public override Type[] GetOptionalCustomModifiers()
172172
public override bool IsEnum => _unmodifiedType.IsEnum;
173173
protected override bool IsPrimitiveImpl() => _unmodifiedType.IsPrimitive;
174174
protected override bool IsByRefImpl() => _unmodifiedType.IsByRef;
175+
public override bool IsGenericParameter => _unmodifiedType.IsGenericParameter;
175176
public override bool IsGenericTypeParameter => _unmodifiedType.IsGenericTypeParameter;
176177
public override bool IsGenericMethodParameter => _unmodifiedType.IsGenericMethodParameter;
178+
public override int GenericParameterPosition => _unmodifiedType.GenericParameterPosition;
177179
protected override bool IsPointerImpl() => _unmodifiedType.IsPointer;
178180
protected override bool IsValueTypeImpl() => _unmodifiedType.IsValueType;
179181
protected override bool IsCOMObjectImpl() => _unmodifiedType.IsCOMObject;

src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/FieldBuilderImpl.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ public override void SetValue(object? obj, object? val, BindingFlags invokeAttr,
113113

114114
public override Type[] GetOptionalCustomModifiers() => _optionalCustomModifiers ?? Type.EmptyTypes;
115115

116+
public override Type GetModifiedFieldType() => FieldType;
117+
116118
#endregion
117119

118120
#region ICustomAttributeProvider Implementation

src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,8 @@ internal void AppendMetadata(MethodBodyStreamEncoder methodBodyEncoder, BlobBuil
184184
}
185185

186186
// Now write all generic parameters in order
187-
genericParams.Sort((x, y) => {
187+
genericParams.Sort((x, y) =>
188+
{
188189
int primary = CodedIndex.TypeOrMethodDef(x._parentHandle).CompareTo(CodedIndex.TypeOrMethodDef(y._parentHandle));
189190
if (primary != 0)
190191
return primary;
@@ -690,6 +691,8 @@ internal void WriteCustomAttributes(List<CustomAttributeWrapper>? customAttribut
690691

691692
private EntityHandle GetTypeReferenceOrSpecificationHandle(Type type)
692693
{
694+
type = type.UnderlyingSystemType;
695+
693696
if (!_typeReferences.TryGetValue(type, out var typeHandle))
694697
{
695698
if (type.HasElementType || type.IsGenericParameter ||
@@ -740,7 +743,7 @@ private EntityHandle GetMemberReferenceHandle(MemberInfo memberInfo)
740743
declaringType = declaringType.MakeGenericType(declaringType.GetGenericArguments());
741744
}
742745

743-
Type fieldType = ((FieldInfo)GetOriginalMemberIfConstructedType(field)).FieldType;
746+
Type fieldType = ((FieldInfo)GetOriginalMemberIfConstructedType(field)).GetModifiedFieldType();
744747
memberHandle = AddMemberReference(field.Name, GetTypeHandle(declaringType),
745748
MetadataSignatureHelper.GetFieldSignature(fieldType, field.GetRequiredCustomModifiers(), field.GetOptionalCustomModifiers(), this));
746749

@@ -791,7 +794,7 @@ private EntityHandle GetMethodReference(MethodInfo methodInfo, Type[] optionalPa
791794
}
792795

793796
private BlobBuilder GetMethodSignature(MethodInfo method, Type[]? optionalParameterTypes) =>
794-
MetadataSignatureHelper.GetMethodSignature(this, ParameterTypes(method.GetParameters()), method.ReturnType,
797+
MetadataSignatureHelper.GetMethodSignature(this, MetadataSignatureHelper.GetParameterTypes(method.GetParameters()), method.ReturnParameter.GetModifiedParameterType(),
795798
GetSignatureConvention(method.CallingConvention), method.GetGenericArguments().Length, !method.IsStatic, optionalParameterTypes);
796799

797800
private BlobBuilder GetMethodArrayMethodSignature(ArrayMethod method) => MetadataSignatureHelper.GetMethodSignature(
@@ -829,23 +832,6 @@ private MemberInfo GetOriginalMemberIfConstructedType(MemberInfo memberInfo)
829832
return memberInfo;
830833
}
831834

832-
private static Type[] ParameterTypes(ParameterInfo[] parameterInfos)
833-
{
834-
if (parameterInfos.Length == 0)
835-
{
836-
return Type.EmptyTypes;
837-
}
838-
839-
Type[] parameterTypes = new Type[parameterInfos.Length];
840-
841-
for (int i = 0; i < parameterInfos.Length; i++)
842-
{
843-
parameterTypes[i] = parameterInfos[i].ParameterType;
844-
}
845-
846-
return parameterTypes;
847-
}
848-
849835
private AssemblyReferenceHandle GetAssemblyReference(Assembly assembly)
850836
{
851837
if (!_assemblyReferences.TryGetValue(assembly, out var handle))
@@ -861,7 +847,7 @@ private AssemblyReferenceHandle GetAssemblyReference(Assembly assembly)
861847
}
862848
else
863849
{
864-
publicKeyOrToken = aName.GetPublicKeyToken();
850+
publicKeyOrToken = aName.GetPublicKeyToken();
865851
}
866852
handle = AddAssemblyReference(aName.Name, aName.Version, aName.CultureName, publicKeyOrToken, assemblyFlags);
867853
_assemblyReferences.Add(assembly, handle);

src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ParameterBuilderImpl.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,7 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan
6868
internal sealed class ParameterInfoWrapper : ParameterInfo
6969
{
7070
private readonly ParameterBuilderImpl _pb;
71-
private readonly Type _type
72-
;
71+
private readonly Type _type;
7372
public ParameterInfoWrapper(ParameterBuilderImpl pb, Type type)
7473
{
7574
_pb = pb;
@@ -87,5 +86,7 @@ public ParameterInfoWrapper(ParameterBuilderImpl pb, Type type)
8786
public override bool HasDefaultValue => _pb._defaultValue != DBNull.Value;
8887

8988
public override object? DefaultValue => HasDefaultValue ? _pb._defaultValue : null;
89+
90+
public override Type GetModifiedParameterType() => ParameterType;
9091
}
9192
}

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ internal static BlobBuilder GetConstructorSignature(ParameterInfo[]? parameters,
4848

4949
retType.Void();
5050

51-
WriteParametersSignature(module, Array.ConvertAll(parameters, p => p.ParameterType), parameterEncoder);
51+
WriteParametersSignature(module, GetParameterTypes(parameters), parameterEncoder);
5252

5353
return constructorSignature;
5454
}
@@ -106,6 +106,23 @@ internal static BlobBuilder GetMethodSignature(ModuleBuilderImpl module, Type[]?
106106
return methodSignature;
107107
}
108108

109+
internal static Type[] GetParameterTypes(ParameterInfo[] parameterInfos)
110+
{
111+
if (parameterInfos.Length == 0)
112+
{
113+
return Type.EmptyTypes;
114+
}
115+
116+
Type[] parameterTypes = new Type[parameterInfos.Length];
117+
118+
for (int i = 0; i < parameterInfos.Length; i++)
119+
{
120+
parameterTypes[i] = parameterInfos[i].GetModifiedParameterType();
121+
}
122+
123+
return parameterTypes;
124+
}
125+
109126
private static void WriteReturnTypeCustomModifiers(CustomModifiersEncoder encoder,
110127
Type[]? requiredModifiers, Type[]? optionalModifiers, ModuleBuilderImpl module)
111128
{
@@ -122,8 +139,10 @@ private static void WriteReturnTypeCustomModifiers(CustomModifiersEncoder encode
122139

123140
private static void WriteCustomModifiers(CustomModifiersEncoder encoder, Type[] customModifiers, bool isOptional, ModuleBuilderImpl module)
124141
{
125-
foreach (Type modifier in customModifiers)
142+
// GetOptionalCustomModifiers and GetRequiredCustomModifiers return modifiers in reverse order
143+
for (int i = customModifiers.Length - 1; i >= 0; i--)
126144
{
145+
Type modifier = customModifiers[i];
127146
encoder.AddModifier(module.GetTypeHandle(modifier), isOptional);
128147
}
129148
}
@@ -295,6 +314,7 @@ private static void WriteSignatureForFunctionPointerType(SignatureTypeEncoder si
295314

296315
private static void WriteSimpleSignature(SignatureTypeEncoder signature, Type type, ModuleBuilderImpl module)
297316
{
317+
type = type.UnderlyingSystemType;
298318
CoreTypeId? typeId = module.GetTypeIdFromCoreTypes(type);
299319

300320
switch (typeId)

src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -633,13 +633,13 @@ public void ReturnTypeAndParameterRequiredOptionalCustomModifiers()
633633
Type[] par0RequiredMods = allModMethod.GetParameters()[0].GetRequiredCustomModifiers();
634634
Type[] par0OptionalMods = allModMethod.GetParameters()[0].GetOptionalCustomModifiers();
635635
Assert.Equal(2, returnReqMods.Length);
636-
Assert.Equal(mlc.CoreAssembly.GetType(typeof(short).FullName), returnReqMods[0]);
637-
Assert.Equal(mlc.CoreAssembly.GetType(typeof(int).FullName), returnReqMods[1]);
636+
Assert.Equal(mlc.CoreAssembly.GetType(typeof(int).FullName), returnReqMods[0]);
637+
Assert.Equal(mlc.CoreAssembly.GetType(typeof(short).FullName), returnReqMods[1]);
638638
Assert.Equal(1, returnOptMods.Length);
639639
Assert.Equal(mlc.CoreAssembly.GetType(typeof(Version).FullName), returnOptMods[0]);
640640
Assert.Equal(cmodsReq1.Length, par0RequiredMods.Length);
641-
Assert.Equal(mlc.CoreAssembly.GetType(cmodsReq1[1].FullName), par0RequiredMods[0]);
642-
Assert.Equal(mlc.CoreAssembly.GetType(cmodsReq1[0].FullName), par0RequiredMods[1]);
641+
Assert.Equal(mlc.CoreAssembly.GetType(cmodsReq1[0].FullName), par0RequiredMods[0]);
642+
Assert.Equal(mlc.CoreAssembly.GetType(cmodsReq1[1].FullName), par0RequiredMods[1]);
643643
Assert.Equal(cmodsOpt1.Length, par0OptionalMods.Length);
644644
Assert.Equal(mlc.CoreAssembly.GetType(cmodsOpt1[0].FullName), par0OptionalMods[0]);
645645
Assert.Equal(cmodsReq2.Length, allModMethod.GetParameters()[1].GetRequiredCustomModifiers().Length);

src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderTests.cs

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,8 @@ public void SaveFunctionPointerFields()
864864
}
865865

866866
[Fact]
867-
public void ConsumeFunctionPointerFields()
867+
[ActiveIssue("https://github.com/dotnet/runtime/issues/2383", TestRuntimes.Mono)]
868+
public void ConsumeFunctionPointerMembers()
868869
{
869870
// public unsafe class Container
870871
// {
@@ -915,16 +916,29 @@ public void ConsumeFunctionPointerFields()
915916
MethodBuilder mainMethod = programType.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static);
916917
mainMethod.SetReturnType(typeof(int));
917918
ILGenerator il = mainMethod.GetILGenerator();
918-
il.Emit(OpCodes.Ldsfld, typeof(ClassWithFunctionPointerFields).GetField("field1"));
919+
il.Emit(OpCodes.Ldsfld, typeof(ClassWithFunctionPointerMembers).GetField("field1"));
920+
il.Emit(OpCodes.Pop);
921+
il.Emit(OpCodes.Ldsfld, typeof(ClassWithFunctionPointerMembers).GetField("field2"));
922+
il.Emit(OpCodes.Pop);
923+
il.Emit(OpCodes.Ldsfld, typeof(ClassWithFunctionPointerMembers).GetField("field3"));
924+
il.Emit(OpCodes.Pop);
925+
il.Emit(OpCodes.Ldsfld, typeof(ClassWithFunctionPointerMembers).GetField("field4"));
926+
il.Emit(OpCodes.Pop);
927+
il.Emit(OpCodes.Ldsfld, typeof(ClassWithFunctionPointerMembers).GetField("field5"));
928+
il.Emit(OpCodes.Pop);
929+
il.Emit(OpCodes.Call, typeof(ClassWithFunctionPointerMembers).GetMethod("Method1"));
930+
il.Emit(OpCodes.Pop);
931+
il.Emit(OpCodes.Call, typeof(ClassWithFunctionPointerMembers).GetMethod("Method2"));
932+
il.Emit(OpCodes.Pop);
933+
il.Emit(OpCodes.Call, typeof(ClassWithFunctionPointerMembers).GetMethod("Method3"));
934+
il.Emit(OpCodes.Pop);
935+
il.Emit(OpCodes.Call, typeof(ClassWithFunctionPointerMembers).GetMethod("Method4"));
936+
il.Emit(OpCodes.Call, typeof(ClassWithFunctionPointerMembers).GetMethod("Method5"));
937+
il.Emit(OpCodes.Pop);
938+
il.Emit(OpCodes.Ldsfld, typeof(GenericClassWithFunctionPointerMembers<int>).GetField("Field"));
939+
il.Emit(OpCodes.Pop);
940+
il.Emit(OpCodes.Call, typeof(GenericClassWithFunctionPointerMembers<Guid>).GetMethod("Method").MakeGenericMethod(typeof(string)));
919941
il.Emit(OpCodes.Pop);
920-
// References to fields with unmanaged calling convention are broken
921-
// [ActiveIssue("https://github.com/dotnet/runtime/issues/120909")]
922-
// il.Emit(OpCodes.Ldsfld, typeof(ClassWithFunctionPointerFields).GetField("field2"));
923-
// il.Emit(OpCodes.Pop);
924-
// il.Emit(OpCodes.Ldsfld, typeof(ClassWithFunctionPointerFields).GetField("field3"));
925-
// il.Emit(OpCodes.Pop);
926-
// il.Emit(OpCodes.Ldsfld, typeof(ClassWithFunctionPointerFields).GetField("field4"));
927-
// il.Emit(OpCodes.Pop);
928942
il.Emit(OpCodes.Call, assembly1FromDisk.GetType("Container").GetMethod("Init"));
929943
il.Emit(OpCodes.Ldc_I4_2);
930944
il.Emit(OpCodes.Ldc_I4_3);
@@ -989,11 +1003,24 @@ public class ClassWithFields : EmptyTestClass
9891003
public byte field2;
9901004
}
9911005

992-
public unsafe class ClassWithFunctionPointerFields
1006+
public unsafe class ClassWithFunctionPointerMembers
9931007
{
994-
public static delegate*<ClassWithFunctionPointerFields> field1;
1008+
public static delegate*<ClassWithFunctionPointerMembers> field1;
9951009
public static delegate* unmanaged<int> field2;
9961010
public static delegate* unmanaged[Cdecl]<Guid> field3;
9971011
public static delegate* unmanaged[Cdecl, SuppressGCTransition]<Vector<int>, Vector<int>> field4;
1012+
public static List<delegate* unmanaged[Stdcall, MemberFunction, SuppressGCTransition]<long>*[]> field5;
1013+
1014+
public static delegate*<int> Method1() => null;
1015+
public static delegate* unmanaged<string> Method2() => null;
1016+
public static delegate* unmanaged[Fastcall]<double> Method3() => null;
1017+
public static delegate* unmanaged[Cdecl]<delegate* unmanaged<int>, Guid> Method4() => null;
1018+
public static delegate* unmanaged[Cdecl]<int> Method5(delegate* unmanaged[Cdecl]<delegate* unmanaged<int>, Guid> funcPtr) => null;
1019+
}
1020+
1021+
public unsafe class GenericClassWithFunctionPointerMembers<T>
1022+
{
1023+
public static delegate* unmanaged[Cdecl]<T> Field;
1024+
public static delegate* unmanaged[Fastcall, MemberFunction]<T, U> Method<U>() => null;
9981025
}
9991026
}

0 commit comments

Comments
 (0)