Skip to content

Commit

Permalink
Apply feedbacks, add method specification handling for constructed me…
Browse files Browse the repository at this point in the history
…thod references
  • Loading branch information
buyaa-n committed Nov 17, 2023
1 parent 502bd66 commit ffd43b6
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<SharedGUID>c5ed3c1d-b572-46f1-8f96-522a85ce1179</SharedGUID>
<StringResourcesName Condition="'$(StringResourcesName)' == ''">System.Private.CoreLib.Strings</StringResourcesName>
<GenerateResourcesSubstitutions>true</GenerateResourcesSubstitutions>

<!-- CA2252: Opt in to preview features before using them (for System.Threading.Lock) -->
<EnablePreviewFeatures>true</EnablePreviewFeatures>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,7 @@ internal override Type[] GetParameterTypes()
public override object[] GetCustomAttributes(bool inherit) { return _ctor.GetCustomAttributes(inherit); }
public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return _ctor.GetCustomAttributes(attributeType, inherit); }
public override bool IsDefined(Type attributeType, bool inherit) { return _ctor.IsDefined(attributeType, inherit); }
public override int MetadataToken
{
get
{
ConstructorBuilder? cb = _ctor as ConstructorBuilder;

if (cb != null)
{
return cb.MetadataToken;
}
else
{
return _ctor.MetadataToken;
}
}
}
public override int MetadataToken => _ctor.MetadataToken;
public override Module Module => _ctor.Module;
#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,7 @@ internal FieldOnTypeBuilderInstantiation(FieldInfo field, TypeBuilderInstantiati
public override object[] GetCustomAttributes(bool inherit) { return _field.GetCustomAttributes(inherit); }
public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return _field.GetCustomAttributes(attributeType, inherit); }
public override bool IsDefined(Type attributeType, bool inherit) { return _field.IsDefined(attributeType, inherit); }
public override int MetadataToken
{
get
{
FieldBuilder? fb = _field as FieldBuilder;

if (fb != null)
{
return fb.MetadataToken;
}
else
{
return _field.MetadataToken;
}
}
}
public override int MetadataToken => _field.MetadataToken;
public override Module Module => _field.Module;
#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ internal MethodBuilderInstantiation(MethodInfo method, Type[] inst)
}
#endregion

#if SYSTEM_PRIVATE_CORELIB
internal override Type[] GetParameterTypes()
{
return _method.GetParameterTypes();
}
#endif

#region MemberBase
public override MemberTypes MemberType => _method.MemberType;
Expand Down Expand Up @@ -82,6 +84,7 @@ public override bool ContainsGenericParameters
}
}

[RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public override MethodInfo MakeGenericMethod(params Type[] arguments)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,7 @@
<data name="Argument_ShouldNotSpecifyExceptionType" xml:space="preserve">
<value>Should not specify exception type for catch clause for filter block.</value>
</data>
<data name="Arg_NotGenericMethodDefinition" xml:space="preserve">
<value>{0} is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="$(CoreLibSharedDir)System\Reflection\Emit\MethodBuilderInstantiation.cs" Link="System\Reflection\Emit\MethodBuilderInstantiation.cs" />
<Compile Include="$(CoreLibSharedDir)System\Reflection\Emit\TypeNameBuilder.cs" Link="System\Reflection\Emit\TypeNameBuilder.cs" />
<Compile Include="System\Reflection\Emit\ConstructorBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\CustomAttributeWrapper.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ public override object Invoke(object? obj, BindingFlags invokeAttr, Binder? bind

[RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public override MethodInfo MakeGenericMethod(params Type[] typeArguments)
=> throw new NotImplementedException();
public override MethodInfo MakeGenericMethod(params Type[] typeArguments) =>
MethodBuilderInstantiation.MakeGenericMethod(this, typeArguments);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal sealed class ModuleBuilderImpl : ModuleBuilder
private readonly AssemblyBuilderImpl _assemblyBuilder;
private readonly Dictionary<Assembly, AssemblyReferenceHandle> _assemblyReferences = new();
private readonly Dictionary<Type, EntityHandle> _typeReferences = new();
private readonly Dictionary<MemberInfo, MemberReferenceHandle> _memberReferences = new();
private readonly Dictionary<MemberInfo, EntityHandle> _memberReferences = new();
private readonly List<TypeBuilderImpl> _typeDefinitions = new();
private readonly Dictionary<ConstructorInfo, MemberReferenceHandle> _ctorReferences = new();
private Dictionary<string, ModuleReferenceHandle>? _moduleReferences;
Expand Down Expand Up @@ -372,13 +372,26 @@ private EntityHandle GetTypeReferenceOrSpecificationHandle(Type type)

private TypeSpecificationHandle AddTypeSpecification(Type type) =>
_metadataBuilder.AddTypeSpecification(
signature: _metadataBuilder.GetOrAddBlob(MetadataSignatureHelper.GetTypeSignature(type, this)));
signature: _metadataBuilder.GetOrAddBlob(MetadataSignatureHelper.GetTypeSpecificationSignature(type, this)));

private MemberReferenceHandle GetMemberReference(MemberInfo member)
private MethodSpecificationHandle AddMethodSpecification(EntityHandle methodHandle, Type[] genericArgs) =>
_metadataBuilder.AddMethodSpecification(
method: methodHandle,
instantiation: _metadataBuilder.GetOrAddBlob(MetadataSignatureHelper.GetMethodSpecificationSignature(genericArgs, this)));

private EntityHandle GetMemberReference(MemberInfo member)
{
if (!_memberReferences.TryGetValue(member, out var memberHandle))
{
memberHandle = AddMemberReference(member.Name, GetTypeReferenceOrSpecificationHandle(member.DeclaringType!), GetMemberSignature(member));
if (member is MethodInfo method && method.IsConstructedGenericMethod)
{
memberHandle = AddMethodSpecification(GetMemberReference(method.GetGenericMethodDefinition()), method.GetGenericArguments());
}
else
{
memberHandle = AddMemberReference(member.Name, GetTypeHandle(member.DeclaringType!), GetMemberSignature(member));
}

_memberReferences.Add(member, memberHandle);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,25 @@ internal static BlobBuilder ConstructorSignatureEncoder(ParameterInfo[]? paramet
return constructorSignature;
}

internal static BlobBuilder GetTypeSignature(Type type, ModuleBuilderImpl module)
internal static BlobBuilder GetTypeSpecificationSignature(Type type, ModuleBuilderImpl module)
{
BlobBuilder typeSignature = new();
WriteSignatureForType(new BlobEncoder(typeSignature).TypeSpecificationSignature(), type, module);
BlobBuilder typeSpecSignature = new();
WriteSignatureForType(new BlobEncoder(typeSpecSignature).TypeSpecificationSignature(), type, module);

return typeSignature;
return typeSpecSignature;
}

internal static BlobBuilder GetMethodSpecificationSignature(Type[] genericArguments, ModuleBuilderImpl module)
{
BlobBuilder methodSpecSignature = new();
GenericTypeArgumentsEncoder encoder = new BlobEncoder(methodSpecSignature).MethodSpecificationSignature(genericArguments.Length);

foreach (Type argument in genericArguments)
{
WriteSignatureForType(encoder.AddArgument(), argument, module);
}

return methodSpecSignature;
}

internal static BlobBuilder MethodSignatureEncoder(ModuleBuilderImpl module, Type[]? parameters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -653,9 +653,7 @@ void Main(int a)
}
}



/*[Fact] // TODO: Resolve MethodBuilderInstantiation access
[Fact]
public void ReferenceConstructedGenericMethod()
{
using (TempFile file = TempFile.Create())
Expand All @@ -672,7 +670,6 @@ public void ReferenceConstructedGenericMethod()
ilg.Emit(OpCodes.Ret);
MethodBuilder mainMethod = type.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static);
ilg = mainMethod.GetILGenerator();
//MethodInfo SampleOfGM = TypeBuilder.GetMethod(type, genericMethod);
MethodInfo GMOfString = genericMethod.MakeGenericMethod(typeof(string));
ilg.Emit(OpCodes.Ldstr, "Hello, world!");
ilg.EmitCall(OpCodes.Call, GMOfString, null);
Expand All @@ -681,11 +678,16 @@ public void ReferenceConstructedGenericMethod()
saveMethod.Invoke(ab, new[] { file.Path });

Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path);
Type myTypeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType");
Assert.True(myTypeFromDisk.IsGenericType);
Assert.True(myTypeFromDisk.IsGenericTypeDefinition);
Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType");
MethodInfo genericMethodFromDisk = typeFromDisk.GetMethod("GM");
Assert.True(genericMethodFromDisk.IsGenericMethod);
Assert.True(genericMethodFromDisk.IsGenericMethodDefinition);
byte[] ilBytes = typeFromDisk.GetMethod("Main").GetMethodBody().GetILAsByteArray();
Assert.Equal(OpCodes.Ldstr.Value, ilBytes[0]);
Assert.Equal(OpCodes.Call.Value, ilBytes[5]);
Assert.Equal(OpCodes.Ret.Value, ilBytes[10]);
}
}*/
}

[Fact]
public void ReferenceConstructedGenericMethodFieldOfConstructedType()
Expand Down Expand Up @@ -727,7 +729,7 @@ public void ReferenceConstructedGenericMethodFieldOfConstructedType()
ilg.EmitCall(OpCodes.Call, GMOfString, null);
ilg.Emit(OpCodes.Ret);
dummy.CreateType();
/* TODO: verify 'MyType<string>.GM<string>("HelloWorld");' emitted correctly after 'MethodBuilderImpl.GetParameters()' implemented
/* Generated IL would like this in C#:
public class MyType<T>
{
public T Field;
Expand All @@ -744,15 +746,37 @@ internal class Dummy
{
public static void Main()
{
MyType<string>.GM<string>("HelloWorld");
MyType<string>.GM("HelloWorld");
}
} */
saveMethod.Invoke(ab, new[] { file.Path });

Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path);
Type myTypeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType");
Module module = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First();
Type myTypeFromDisk = module.GetType("MyType");
Assert.True(myTypeFromDisk.IsGenericType);
Assert.True(myTypeFromDisk.IsGenericTypeDefinition);
Assert.Equal("T", myTypeFromDisk.GetGenericArguments()[0].Name);
Assert.Equal("T", myTypeFromDisk.GetField("Field").FieldType.Name);
MethodInfo genericMethodFromDisk = myTypeFromDisk.GetMethod("GM");
Assert.True(genericMethodFromDisk.IsGenericMethod);
Assert.True(genericMethodFromDisk.IsGenericMethodDefinition);
Assert.Equal(1, genericMethodFromDisk.GetMethodBody().LocalVariables.Count);
Assert.Equal("MyType[U]", genericMethodFromDisk.GetMethodBody().LocalVariables[0].LocalType.ToString());
byte[] gmIlBytes = genericMethodFromDisk.GetMethodBody().GetILAsByteArray();
Assert.Equal(OpCodes.Newobj.Value, gmIlBytes[0]);
Assert.Equal(OpCodes.Stloc_0.Value, gmIlBytes[5]);
Assert.Equal(OpCodes.Ldloc_0.Value, gmIlBytes[6]);
Assert.Equal(OpCodes.Ldarg_0.Value, gmIlBytes[7]);
Assert.Equal(OpCodes.Stfld.Value, gmIlBytes[8]);
Assert.Equal(OpCodes.Ldloc_0.Value, gmIlBytes[13]);
Assert.Equal(OpCodes.Ldfld.Value, gmIlBytes[14]);
Assert.Equal(OpCodes.Box.Value, gmIlBytes[19]);
Assert.Equal(OpCodes.Call.Value, gmIlBytes[24]);
Assert.Equal(OpCodes.Ret.Value, gmIlBytes[29]);
byte[] ilBytes = module.GetType("Dummy").GetMethod("Main").GetMethodBody().GetILAsByteArray();
Assert.Equal(OpCodes.Ldstr.Value, ilBytes[0]);
Assert.Equal(OpCodes.Call.Value, ilBytes[5]);
Assert.Equal(OpCodes.Ret.Value, ilBytes[10]);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,6 @@ internal static void AssertMethods(MethodInfo[] sourceMethods, MethodInfo[] meth
{
MethodInfo sourceMethod = sourceMethods[j];
MethodInfo methodFromDisk = methodsFromDisk[j];
if (methodFromDisk.Name == ".ctor")
continue;

Assert.Equal(sourceMethod.Name, methodFromDisk.Name);
Assert.Equal(sourceMethod.Attributes, methodFromDisk.Attributes);
Expand Down

0 comments on commit ffd43b6

Please sign in to comment.