Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implement MethodBuilder.GetParameters() using a ParameterInfoWrapper
  • Loading branch information
buyaa-n committed Nov 16, 2023
commit cca300a153e4e635d8fe3fecb13371d7c2d46d47
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public override Type[] GetGenericParameterConstraints() =>
public override bool IsGenericParameter => true;
public override bool IsConstructedGenericType => false;
public override bool ContainsGenericParameters => _type.ContainsGenericParameters;
public override MethodBase? DeclaringMethod => throw new NotImplementedException();
public override MethodBase? DeclaringMethod => _type.DeclaringMethod;
public override Type? BaseType => _parent;
public override RuntimeTypeHandle TypeHandle => throw new NotSupportedException();
public override Guid GUID => throw new NotSupportedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace System.Reflection.Emit
internal sealed class MethodBuilderImpl : MethodBuilder
{
private Type _returnType;
private Type[]? _parameterTypes;
internal Type[]? _parameterTypes;
private readonly ModuleBuilderImpl _module;
private readonly string _name;
private readonly CallingConventions _callingConventions;
Expand All @@ -26,7 +26,7 @@ internal sealed class MethodBuilderImpl : MethodBuilder

internal DllImportData? _dllImportData;
internal List<CustomAttributeWrapper>? _customAttributes;
internal ParameterBuilderImpl[]? _parameters;
internal ParameterBuilderImpl[]? _parameterBuilders;
internal MethodDefinitionHandle _handle;

internal MethodBuilderImpl(string name, MethodAttributes attributes, CallingConventions callingConventions, Type? returnType,
Expand All @@ -53,7 +53,7 @@ internal MethodBuilderImpl(string name, MethodAttributes attributes, CallingConv
if (parameterTypes != null)
{
_parameterTypes = new Type[parameterTypes.Length];
_parameters = new ParameterBuilderImpl[parameterTypes.Length + 1]; // parameter 0 reserved for return type
_parameterBuilders = new ParameterBuilderImpl[parameterTypes.Length + 1]; // parameter 0 reserved for return type
for (int i = 0; i < parameterTypes.Length; i++)
{
ArgumentNullException.ThrowIfNull(_parameterTypes[i] = parameterTypes[i], nameof(parameterTypes));
Expand Down Expand Up @@ -126,14 +126,18 @@ protected override GenericTypeParameterBuilder[] DefineGenericParametersCore(par

protected override ParameterBuilder DefineParameterCore(int position, ParameterAttributes attributes, string? strParamName)
{
_declaringType.ThrowIfCreated();

if (position > 0 && (_parameterTypes == null || position > _parameterTypes.Length))
{
throw new ArgumentOutOfRangeException(SR.ArgumentOutOfRange_ParamSequence);
}

_parameters ??= new ParameterBuilderImpl[1];
_parameterBuilders ??= new ParameterBuilderImpl[1];

attributes &= ~ParameterAttributes.ReservedMask;
ParameterBuilderImpl parameter = new ParameterBuilderImpl(this, position, attributes, strParamName);
_parameters[position] = parameter;
_parameterBuilders[position] = parameter;
return parameter;
}

Expand Down Expand Up @@ -198,8 +202,10 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan

protected override void SetImplementationFlagsCore(MethodImplAttributes attributes)
{
_declaringType.ThrowIfCreated();
_methodImplFlags = attributes;
}

protected override void SetSignatureCore(Type? returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers, Type[]? parameterTypes,
Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers)
{
Expand All @@ -211,14 +217,15 @@ protected override void SetSignatureCore(Type? returnType, Type[]? returnTypeReq
if (parameterTypes != null)
{
_parameterTypes = new Type[parameterTypes.Length];
_parameters = new ParameterBuilderImpl[parameterTypes.Length + 1]; // parameter 0 reserved for return type
_parameterBuilders = new ParameterBuilderImpl[parameterTypes.Length + 1]; // parameter 0 reserved for return type
for (int i = 0; i < parameterTypes.Length; i++)
{
ArgumentNullException.ThrowIfNull(_parameterTypes[i] = parameterTypes[i], nameof(parameterTypes));
}
}
// TODO: Add support for other parameters: returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers, parameterTypeRequiredCustomModifiers and parameterTypeOptionalCustomModifiers
}

public override string Name => _name;
public override MethodAttributes Attributes => _attributes;
public override CallingConventions CallingConvention => _callingConventions;
Expand Down Expand Up @@ -250,7 +257,34 @@ protected override void SetSignatureCore(Type? returnType, Type[]? returnTypeReq
public override MethodImplAttributes GetMethodImplementationFlags()
=> _methodImplFlags;

public override ParameterInfo[] GetParameters() => Array.Empty<ParameterInfo>(); // TODO: Workaround until derive the ParameterBuilder from ParameterInfo
public override ParameterInfo[] GetParameters()
{
// This is called from ILGenerator when Emit(OpCode, ConstructorInfo) when the ctor is
// instance of 'ConstructorOnTypeBuilderInstantiation', so we could not throw here even
// the type was not baked. Runtime implementation throws when the type is not baked.

if (_parameterTypes == null)
{
return Array.Empty<ParameterInfo>();
}

_parameterBuilders ??= new ParameterBuilderImpl[_parameterTypes.Length + 1]; // parameter 0 reserved for return type
ParameterInfo[] parameters = new ParameterInfo[_parameterTypes.Length];

for (int i = 0; i < _parameterTypes.Length; i++)
{
if (_parameterBuilders[i + 1] == null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When is the element null in this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the parameters created with parameterTypes array:

if (parameterTypes != null)
{
_parameterTypes = new Type[parameterTypes.Length];
_parameterBuilders = new ParameterBuilderImpl[parameterTypes.Length + 1]; // parameter 0 reserved for return type
for (int i = 0; i < parameterTypes.Length; i++)
{
ArgumentNullException.ThrowIfNull(_parameterTypes[i] = parameterTypes[i], nameof(parameterTypes));
}

but not explicitly defined with DefineParameterCore(...)

{
parameters[i] = new ParameterInfoWrapper(new ParameterBuilderImpl(this, i, ParameterAttributes.None, null), _parameterTypes[i]);
}
else
{
parameters[i] = new ParameterInfoWrapper(_parameterBuilders[i + 1], _parameterTypes[i]);
}
}

return parameters;
}

public override object Invoke(object? obj, BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture)
=> throw new NotSupportedException(SR.NotSupported_DynamicModule);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,9 @@ private void WriteMethods(List<MethodBuilderImpl> methods, List<GenericTypeParam
}
}

if (method._parameters != null)
if (method._parameterBuilders != null)
{
foreach (ParameterBuilderImpl parameter in method._parameters)
foreach (ParameterBuilderImpl parameter in method._parameterBuilders)
{
if (parameter != null)
{
Expand Down Expand Up @@ -272,6 +272,7 @@ private void WriteMethods(List<MethodBuilderImpl> methods, List<GenericTypeParam
}
}
}

private void FillMemberReferences(ILGeneratorImpl il)
{
foreach (KeyValuePair<MemberInfo, BlobWriter> pair in il.GetMemberReferences())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ internal sealed class ParameterBuilderImpl : ParameterBuilder
{
private readonly string? _name;
private readonly int _position;
private readonly MethodBuilderImpl _methodBuilder;
private ParameterAttributes _attributes;
internal readonly MethodBuilderImpl _methodBuilder;
internal ParameterAttributes _attributes;

internal List<CustomAttributeWrapper>? _customAttributes;
internal MarshallingData? _marshallingData;
Expand Down Expand Up @@ -60,4 +60,28 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan
_customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute));
}
}

internal sealed class ParameterInfoWrapper : ParameterInfo
{
private readonly ParameterBuilderImpl _pb;
private readonly Type _type
;
public ParameterInfoWrapper(ParameterBuilderImpl pb, Type type)
{
_pb = pb;
_type = type;
}

public override ParameterAttributes Attributes => _pb._attributes;

public override string? Name => _pb.Name;

public override int Position => _pb.Position;

public override Type ParameterType => _type;

public override bool HasDefaultValue => _pb._defaultValue != DBNull.Value;

public override object? DefaultValue => HasDefaultValue ? _pb._defaultValue : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ protected override TypeInfo CreateTypeInfoCore()
return this;
}

private void ThrowIfCreated()
internal void ThrowIfCreated()
{
if (_isCreated)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,10 @@ public void DefineDefaultConstructor_GenericParentCreated_Works()
constructorILGenerator.Emit(OpCodes.Ret);
type.CreateType();

/* TODO: Enable this when we can get/create parameters from MethodBuilder
Type genericParent = type.MakeGenericType(typeof(int));
TypeBuilder derived = ((ModuleBuilder)type.Module).DefineType("Derived");
derived.SetParent(genericParent);
derived.DefineDefaultConstructor(MethodAttributes.Public);*/
derived.DefineDefaultConstructor(MethodAttributes.Public);

Type genericList = typeof(List<>).MakeGenericType(typeof(int));
TypeBuilder type2 = ab.GetDynamicModule("MyModule").DefineType("Type2");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,6 @@ public void LocalBuilderMultipleTypesWithMultipleMethodsWithLocals()
longMethodIL.Emit(OpCodes.Ret);
anotherType.CreateType();
saveMethod.Invoke(ab, new object[] { file.Path });
Console.WriteLine(file.Path);

Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path);
Module moduleFromFile = assemblyFromDisk.Modules.First();
Expand Down Expand Up @@ -654,8 +653,42 @@ void Main(int a)
}
}



/*[Fact] // TODO: Resolve MethodBuilderInstantiation access
public void ReferenceConstructedGenericMethod()
{
using (TempFile file = TempFile.Create())
{
AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod);
ConstructorBuilder ctor = type.DefineDefaultConstructor(MethodAttributes.Public);
MethodBuilder genericMethod = type.DefineMethod("GM", MethodAttributes.Public | MethodAttributes.Static);
GenericTypeParameterBuilder[] methodParams = genericMethod.DefineGenericParameters("U");
genericMethod.SetSignature(null, null, null, new[] { methodParams[0] }, null, null);
ILGenerator ilg = genericMethod.GetILGenerator();
MethodInfo writeLineObj = typeof(Console).GetMethod("WriteLine", new[] { typeof(object) });
ilg.Emit(OpCodes.Ldarg_0);
ilg.EmitCall(OpCodes.Call, writeLineObj, null);
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);
ilg.Emit(OpCodes.Ret);
type.CreateType();
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);
}
}*/

[Fact]
public void ReferenceConstructedMethodFieldTest()
public void ReferenceConstructedGenericMethodFieldOfConstructedType()
{
using (TempFile file = TempFile.Create())
{
Expand Down Expand Up @@ -717,9 +750,9 @@ public static void Main()
saveMethod.Invoke(ab, new[] { file.Path });

Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path);
Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType");
Assert.True(typeFromDisk.IsGenericType);
Assert.True(typeFromDisk.IsGenericTypeDefinition);
Type myTypeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType");
Assert.True(myTypeFromDisk.IsGenericType);
Assert.True(myTypeFromDisk.IsGenericTypeDefinition);
}
}

Expand Down