diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index b5cd4894cd5be4..3b82e34fce48fa 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -163,7 +163,6 @@
-
@@ -172,6 +171,7 @@
+
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeMethodBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeMethodBuilder.cs
index b824378c665e6a..bac45a0c5484f4 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeMethodBuilder.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeMethodBuilder.cs
@@ -646,7 +646,7 @@ protected override ParameterBuilder DefineParameterCore(int position, ParameterA
throw new ArgumentOutOfRangeException(SR.ArgumentOutOfRange_ParamSequence);
attributes &= ~ParameterAttributes.ReservedMask;
- return new ParameterBuilder(this, position, attributes, strParamName);
+ return new RuntimeParameterBuilder(this, position, attributes, strParamName);
}
protected override void SetImplementationFlagsCore(MethodImplAttributes attributes)
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeParameterBuilder.cs
similarity index 61%
rename from src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.cs
rename to src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeParameterBuilder.cs
index 9700939f2ec373..71980345a00776 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeParameterBuilder.cs
@@ -5,10 +5,10 @@
namespace System.Reflection.Emit
{
- public class ParameterBuilder
+ internal sealed class RuntimeParameterBuilder : ParameterBuilder
{
// Set the default value of the parameter
- public virtual void SetConstant(object? defaultValue)
+ public override void SetConstant(object? defaultValue)
{
RuntimeTypeBuilder.SetConstantValue(
_methodBuilder.GetModuleBuilder(),
@@ -17,12 +17,8 @@ public virtual void SetConstant(object? defaultValue)
defaultValue);
}
- // Use this function if client decides to form the custom attribute blob themselves
- public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute)
{
- ArgumentNullException.ThrowIfNull(con);
- ArgumentNullException.ThrowIfNull(binaryAttribute);
-
RuntimeTypeBuilder.DefineCustomAttribute(
_methodBuilder.GetModuleBuilder(),
_token,
@@ -30,15 +26,7 @@ public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
binaryAttribute);
}
- // Use this function if client wishes to build CustomAttribute using CustomAttributeBuilder
- public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
- {
- ArgumentNullException.ThrowIfNull(customBuilder);
-
- customBuilder.CreateCustomAttribute((RuntimeModuleBuilder)(_methodBuilder.GetModule()), _token);
- }
-
- internal ParameterBuilder(
+ internal RuntimeParameterBuilder(
RuntimeMethodBuilder methodBuilder,
int sequence,
ParameterAttributes attributes,
@@ -62,17 +50,11 @@ internal int GetToken()
return _token;
}
- public virtual string? Name => _name;
-
- public virtual int Position => _position;
-
- public virtual int Attributes => (int)_attributes;
-
- public bool IsIn => (_attributes & ParameterAttributes.In) != 0;
+ public override string? Name => _name;
- public bool IsOut => (_attributes & ParameterAttributes.Out) != 0;
+ public override int Position => _position;
- public bool IsOptional => (_attributes & ParameterAttributes.Optional) != 0;
+ public override int Attributes => (int)_attributes;
private readonly string? _name;
private readonly int _position;
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
index dd0e469c284301..e400551f9a50ba 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
@@ -145,7 +145,6 @@
-
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.cs
deleted file mode 100644
index 2c02ff1f1ea7b6..00000000000000
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace System.Reflection.Emit
-{
- public partial class ParameterBuilder
- {
- internal ParameterBuilder()
- {
- // Prevent generating a default constructor
- }
-
- public virtual int Attributes
- {
- get
- {
- return default;
- }
- }
-
- public bool IsIn
- {
- get
- {
- return default;
- }
- }
-
- public bool IsOptional
- {
- get
- {
- return default;
- }
- }
-
- public bool IsOut
- {
- get
- {
- return default;
- }
- }
-
- public virtual string Name
- {
- get
- {
- return default;
- }
- }
-
- public virtual int Position
- {
- get
- {
- return default;
- }
- }
-
- public virtual void SetConstant(object defaultValue)
- {
- }
-
- public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
- {
- }
-
- public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
- {
- }
- }
-}
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 0759d0370079f0..7859d2b8ccff92 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -646,6 +646,7 @@
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.cs
new file mode 100644
index 00000000000000..c7c7e81e95ff97
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Reflection.Emit
+{
+ public abstract partial class ParameterBuilder
+ {
+ protected ParameterBuilder() { }
+ public virtual int Attributes => throw new NotImplementedException();
+ public bool IsIn => ((ParameterAttributes)Attributes & ParameterAttributes.In) != 0;
+ public bool IsOptional => ((ParameterAttributes)Attributes & ParameterAttributes.Optional) != 0;
+ public bool IsOut => ((ParameterAttributes)Attributes & ParameterAttributes.Out) != 0;
+ public virtual string? Name => throw new NotImplementedException();
+ public virtual int Position => throw new NotImplementedException();
+ public virtual void SetConstant(object? defaultValue) => throw new NotImplementedException();
+ public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
+ {
+ ArgumentNullException.ThrowIfNull(con);
+ ArgumentNullException.ThrowIfNull(binaryAttribute);
+
+ SetCustomAttributeCore(con, binaryAttribute);
+ }
+ protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute);
+ public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+ {
+ ArgumentNullException.ThrowIfNull(customBuilder);
+
+ SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
+ }
+ }
+}
diff --git a/src/libraries/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.cs b/src/libraries/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.cs
index fbcc94202c48b8..1a200d8a56f71e 100644
--- a/src/libraries/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.cs
+++ b/src/libraries/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.cs
@@ -72,9 +72,9 @@ internal LocalBuilder() { }
public override int LocalIndex { get { throw null; } }
public override System.Type LocalType { get { throw null; } }
}
- public partial class ParameterBuilder
+ public abstract partial class ParameterBuilder
{
- internal ParameterBuilder() { }
+ protected ParameterBuilder() { }
public virtual int Attributes { get { throw null; } }
public bool IsIn { get { throw null; } }
public bool IsOptional { get { throw null; } }
@@ -84,6 +84,7 @@ internal ParameterBuilder() { }
public virtual void SetConstant(object? defaultValue) { }
public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { }
public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { }
+ protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute);
}
public sealed partial class SignatureHelper
{
diff --git a/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx b/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx
index dcbd221db545cb..02f0c2865c2e8f 100644
--- a/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx
+++ b/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx
@@ -126,9 +126,6 @@
Interface must be declared abstract.
-
- The signature {0} is not supported.
-
Assembly needs at least one module defined.
@@ -141,11 +138,11 @@
The invoked member is not supported in a dynamic module.
-
+
The type code may not be used as a type argument of a custom attribute .
-
- Custom attribute '{0}' doesn't contain a field named '{1}'.
+
+ 'UnmanagedType.{0}' named parameter is only valid for fields.
Custom attribute '{0}' data length is only '{1}'.
@@ -162,4 +159,16 @@
DllName cannot be empty.
+
+ The specified parameter index is not in range.
+
+
+ Invalid constructor argument {0} provided for MarshalAs atttribute.
+
+
+ Named parameter {0} is not valid for UnmanagedType.{1} type.
+
+
+ SizeConst parameter must be specified for UnmanagedType.ByValTStr type.
+
\ No newline at end of file
diff --git a/src/libraries/System.Reflection.Emit/src/System.Reflection.Emit.csproj b/src/libraries/System.Reflection.Emit/src/System.Reflection.Emit.csproj
index a647e5707b5cea..2e7f66ddc2a37c 100644
--- a/src/libraries/System.Reflection.Emit/src/System.Reflection.Emit.csproj
+++ b/src/libraries/System.Reflection.Emit/src/System.Reflection.Emit.csproj
@@ -10,6 +10,8 @@
+
+
diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/CustomAttributeWrapper.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/CustomAttributeWrapper.cs
index 2026b79c74e263..01813788bf7716 100644
--- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/CustomAttributeWrapper.cs
+++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/CustomAttributeWrapper.cs
@@ -2,8 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Buffers.Binary;
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics;
using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+using System.Runtime.InteropServices;
namespace System.Reflection.Emit
{
@@ -171,7 +173,7 @@ private static Type ElementTypeToType(PrimitiveSerializationTypeCode elementType
PrimitiveSerializationTypeCode.Single => typeof(float),
PrimitiveSerializationTypeCode.Double => typeof(double),
PrimitiveSerializationTypeCode.String => typeof(string),
- _ => throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute"),
+ _ => throw new ArgumentException(SR.Argument_InvalidTypeCodeForTypeArgument, "binaryAttribute"),
};
}
}
diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/FieldBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/FieldBuilderImpl.cs
index 3025818ef1a001..0e4fe230fb8cd2 100644
--- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/FieldBuilderImpl.cs
+++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/FieldBuilderImpl.cs
@@ -19,7 +19,7 @@ internal sealed class FieldBuilderImpl : FieldBuilder
private readonly Type _fieldType;
private FieldAttributes _attributes;
- internal MarshallingInfo? _marshallingInfo;
+ internal MarshallingData? _marshallingData;
internal int _offset;
internal List? _customAttributes;
@@ -41,19 +41,19 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan
case "System.Runtime.InteropServices.FieldOffsetAttribute":
Debug.Assert(binaryAttribute.Length >= 6);
_offset = BinaryPrimitives.ReadInt32LittleEndian(binaryAttribute.Slice(2));
- return;
+ return;
case "System.NonSerializedAttribute":
#pragma warning disable SYSLIB0050 // 'FieldAttributes.NotSerialized' is obsolete: 'Formatter-based serialization is obsolete and should not be used'.
_attributes |= FieldAttributes.NotSerialized;
#pragma warning restore SYSLIB0050
- return;
+ return;
case "System.Runtime.CompilerServices.SpecialNameAttribute":
_attributes |= FieldAttributes.SpecialName;
- return;
+ return;
case "System.Runtime.InteropServices.MarshalAsAttribute":
_attributes |= FieldAttributes.HasFieldMarshal;
- _marshallingInfo = MarshallingInfo.ParseMarshallingInfo(con, binaryAttribute);
- return;
+ _marshallingData = MarshallingData.CreateMarshallingData(con, binaryAttribute, isField : true);
+ return;
}
_customAttributes ??= new List();
@@ -101,386 +101,5 @@ public override void SetValue(object? obj, object? val, BindingFlags invokeAttr,
public override bool IsDefined(Type attributeType, bool inherit) => throw new NotSupportedException(SR.NotSupported_DynamicModule);
#endregion
-
- internal sealed class MarshallingInfo
- {
- internal UnmanagedType _marshalType;
- private int _marshalArrayElementType; // safe array: VarEnum; array: UnmanagedType
- private int _marshalArrayElementCount; // number of elements in an array, length of a string, or Unspecified
- private int _marshalParameterIndex; // index of parameter that specifies array size (short) or IID (int), or Unspecified
- private object? _marshalTypeNameOrSymbol; // custom marshaller: string or Type; safe array: element type
- private string? _marshalCookie;
-
- internal const int Invalid = -1;
- private const UnmanagedType InvalidUnmanagedType = (UnmanagedType)Invalid;
- private const VarEnum InvalidVariantType = (VarEnum)Invalid;
- internal const int MaxMarshalInteger = 0x1fffffff;
-
- internal BlobHandle PopulateMarshallingBlob(MetadataBuilder builder)
- {
- var blobBuilder = new BlobBuilder();
- SerializeMarshallingDescriptor(blobBuilder);
- return builder.GetOrAddBlob(blobBuilder);
-
- }
-
- // The logic imported from https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs#L3543
- internal void SerializeMarshallingDescriptor(BlobBuilder writer)
- {
- writer.WriteCompressedInteger((int)_marshalType);
- switch (_marshalType)
- {
- case UnmanagedType.ByValArray: // NATIVE_TYPE_FIXEDARRAY
- Debug.Assert(_marshalArrayElementCount >= 0);
- writer.WriteCompressedInteger(_marshalArrayElementCount);
- if (_marshalArrayElementType >= 0)
- {
- writer.WriteCompressedInteger(_marshalArrayElementType);
- }
- break;
- case UnmanagedType.CustomMarshaler:
- writer.WriteUInt16(0); // padding
-
- switch (_marshalTypeNameOrSymbol)
- {
- case Type type:
- writer.WriteSerializedString(type.FullName); // or AssemblyQualifiedName?
- break;
- case null:
- writer.WriteByte(0);
- break;
- default:
- writer.WriteSerializedString((string)_marshalTypeNameOrSymbol);
- break;
- }
-
- if (_marshalCookie != null)
- {
- writer.WriteSerializedString(_marshalCookie);
- }
- else
- {
- writer.WriteByte(0);
- }
- break;
- case UnmanagedType.LPArray: // NATIVE_TYPE_ARRAY
- Debug.Assert(_marshalArrayElementType >= 0);
- writer.WriteCompressedInteger(_marshalArrayElementType);
- if (_marshalParameterIndex >= 0)
- {
- writer.WriteCompressedInteger(_marshalParameterIndex);
- if (_marshalArrayElementCount >= 0)
- {
- writer.WriteCompressedInteger(_marshalArrayElementCount);
- writer.WriteByte(1); // The parameter number is valid
- }
- }
- else if (_marshalArrayElementCount >= 0)
- {
- writer.WriteByte(0); // Dummy parameter value emitted so that NumberOfElements can be in a known position
- writer.WriteCompressedInteger(_marshalArrayElementCount);
- writer.WriteByte(0); // The parameter number is not valid
- }
- break;
- case UnmanagedType.SafeArray:
- VarEnum safeArrayElementSubtype = (VarEnum)_marshalArrayElementType;
- if (safeArrayElementSubtype >= 0)
- {
- writer.WriteCompressedInteger((int)safeArrayElementSubtype);
-
- if (_marshalTypeNameOrSymbol is Type elementType)
- {
- writer.WriteSerializedString(elementType.FullName);
- }
- }
- break;
- case UnmanagedType.ByValTStr: // NATIVE_TYPE_FIXEDSYSSTRING
- writer.WriteCompressedInteger(_marshalArrayElementCount);
- break;
-
- case UnmanagedType.Interface:
- case UnmanagedType.IDispatch:
- case UnmanagedType.IUnknown:
- if (_marshalParameterIndex >= 0)
- {
- writer.WriteCompressedInteger(_marshalParameterIndex);
- }
- break;
- }
- }
-
- internal void SetMarshalAsCustom(object typeSymbolOrName, string? cookie)
- {
- _marshalType = UnmanagedType.CustomMarshaler;
- _marshalTypeNameOrSymbol = typeSymbolOrName;
- _marshalCookie = cookie;
- }
-
- internal void SetMarshalAsComInterface(UnmanagedType unmanagedType, int? parameterIndex)
- {
- Debug.Assert(parameterIndex == null || parameterIndex >= 0 && parameterIndex <= MaxMarshalInteger);
-
- _marshalType = unmanagedType;
- _marshalParameterIndex = parameterIndex ?? Invalid;
- }
-
- internal void SetMarshalAsArray(UnmanagedType? elementType, int? elementCount, short? parameterIndex)
- {
- Debug.Assert(elementCount == null || elementCount >= 0 && elementCount <= MaxMarshalInteger);
- Debug.Assert(parameterIndex == null || parameterIndex >= 0);
-
- _marshalType = UnmanagedType.LPArray;
- _marshalArrayElementType = (int)(elementType ?? (UnmanagedType)0x50);
- _marshalArrayElementCount = elementCount ?? Invalid;
- _marshalParameterIndex = parameterIndex ?? Invalid;
- }
-
- internal void SetMarshalAsFixedArray(UnmanagedType? elementType, int? elementCount)
- {
- Debug.Assert(elementCount == null || elementCount >= 0 && elementCount <= MaxMarshalInteger);
- Debug.Assert(elementType == null || elementType >= 0 && (int)elementType <= MaxMarshalInteger);
-
- _marshalType = UnmanagedType.ByValArray;
- _marshalArrayElementType = (int)(elementType ?? InvalidUnmanagedType);
- _marshalArrayElementCount = elementCount ?? Invalid;
- }
-
- internal void SetMarshalAsSafeArray(VarEnum? elementType, Type? type)
- {
- Debug.Assert(elementType == null || elementType >= 0 && (int)elementType <= MaxMarshalInteger);
-
- _marshalType = UnmanagedType.SafeArray;
- _marshalArrayElementType = (int)(elementType ?? InvalidVariantType);
- _marshalTypeNameOrSymbol = type;
- }
-
- internal void SetMarshalAsFixedString(int elementCount)
- {
- Debug.Assert(elementCount >= 0 && elementCount <= MaxMarshalInteger);
-
- _marshalType = UnmanagedType.ByValTStr;
- _marshalArrayElementCount = elementCount;
- }
-
- internal void SetMarshalAsSimpleType(UnmanagedType type)
- {
- Debug.Assert(type >= 0 && (int)type <= MaxMarshalInteger);
- _marshalType = type;
- }
-
- // The logic imported from https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/Symbols/Attributes/MarshalAsAttributeDecoder.cs
- internal static MarshallingInfo ParseMarshallingInfo(ConstructorInfo con, ReadOnlySpan binaryAttribute)
- {
- CustomAttributeInfo attributeInfo = CustomAttributeInfo.DecodeCustomAttribute(con, binaryAttribute);
- MarshallingInfo info = new();
- UnmanagedType unmanagedType;
-
- if (attributeInfo._ctorArgs[0] is short shortValue)
- {
- unmanagedType = (UnmanagedType)shortValue;
- }
- else
- {
- unmanagedType = (UnmanagedType)attributeInfo._ctorArgs[0]!;
- }
-
- switch (unmanagedType)
- {
- case UnmanagedType.CustomMarshaler:
- DecodeMarshalAsCustom(attributeInfo._namedParamNames, attributeInfo._namedParamValues, info);
- break;
- case UnmanagedType.Interface:
- case UnmanagedType.IDispatch:
- case UnmanagedType.IUnknown:
- DecodeMarshalAsComInterface(attributeInfo._namedParamNames, attributeInfo._namedParamValues, unmanagedType, info);
- break;
- case UnmanagedType.LPArray:
- DecodeMarshalAsArray(attributeInfo._namedParamNames, attributeInfo._namedParamValues, isFixed: false, info);
- break;
- case UnmanagedType.ByValArray:
- DecodeMarshalAsArray(attributeInfo._namedParamNames, attributeInfo._namedParamValues, isFixed: true, info);
- break;
- case UnmanagedType.SafeArray:
- DecodeMarshalAsSafeArray(attributeInfo._namedParamNames, attributeInfo._namedParamValues, info);
- break;
- case UnmanagedType.ByValTStr:
- DecodeMarshalAsFixedString(attributeInfo._namedParamNames, attributeInfo._namedParamValues, info);
- break;
-#pragma warning disable CS0618 // Type or member is obsolete
- case UnmanagedType.VBByRefStr:
-#pragma warning restore CS0618
- // named parameters ignored with no error
- info.SetMarshalAsSimpleType(unmanagedType);
- break;
- default:
- if ((int)unmanagedType < 0 || (int)unmanagedType > MaxMarshalInteger)
- {
- throw new ArgumentException(SR.Argument_InvalidTypeArgument, nameof(binaryAttribute));
- }
- else
- {
- // named parameters ignored with no error
- info.SetMarshalAsSimpleType(unmanagedType);
- }
- break;
- }
-
- return info;
- }
-
- private static void DecodeMarshalAsFixedString(string[] paramNames, object?[] values, MarshallingInfo info)
- {
- int elementCount = -1;
-
- for (int i = 0; i < paramNames.Length; i++)
- {
- switch (paramNames[i])
- {
- case "SizeConst":
- elementCount = (int)values[i]!;
- break;
- case "ArraySubType":
- case "SizeParamIndex":
- throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute");
- // other parameters ignored with no error
- }
- }
-
- if (elementCount < 0)
- {
- // SizeConst must be specified:
- throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute");
- }
-
- info.SetMarshalAsFixedString(elementCount);
- }
-
- private static void DecodeMarshalAsSafeArray(string[] paramNames, object?[] values, MarshallingInfo info)
- {
- VarEnum? elementTypeVariant = null;
- Type? elementType = null;
- int symbolIndex = -1;
-
- for (int i = 0; i < paramNames.Length; i++)
- {
- switch (paramNames[i])
- {
- case "SafeArraySubType":
- elementTypeVariant = (VarEnum)values[i]!;
- break;
- case "SafeArrayUserDefinedSubType":
- elementType = (Type?)values[i];
- symbolIndex = i;
- break;
- case "ArraySubType":
- case "SizeConst":
- case "SizeParamIndex":
- throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute");
- // other parameters ignored with no error
- }
- }
-
- switch (elementTypeVariant)
- {
- case VarEnum.VT_DISPATCH:
- case VarEnum.VT_UNKNOWN:
- case VarEnum.VT_RECORD:
- // only these variants accept specification of user defined subtype
- break;
-
- default:
- if (elementTypeVariant != null && symbolIndex >= 0)
- {
- throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute");
- }
- else
- {
- // type ignored:
- elementType = null;
- }
- break;
- }
-
- info.SetMarshalAsSafeArray(elementTypeVariant, elementType);
- }
-
- private static void DecodeMarshalAsArray(string[] paramNames, object?[] values, bool isFixed, MarshallingInfo info)
- {
- UnmanagedType? elementType = null;
- int? elementCount = isFixed ? 1 : null;
- short? parameterIndex = null;
-
- for (int i = 0; i < paramNames.Length; i++)
- {
- switch (paramNames[i])
- {
- case "ArraySubType":
- elementType = (UnmanagedType)values[i]!;
- break;
- case "SizeConst":
- elementCount = (int?)values[i];
- break;
- case "SizeParamIndex":
- if (isFixed)
- {
- goto case "SafeArraySubType";
- }
- parameterIndex = (short?)values[i];
- break;
- case "SafeArraySubType":
- throw new ArgumentException(SR.Argument_InvalidTypeArgument, "binaryAttribute");
- // other parameters ignored with no error
- }
- }
-
- if (isFixed)
- {
- info.SetMarshalAsFixedArray(elementType, elementCount);
- }
- else
- {
- info.SetMarshalAsArray(elementType, elementCount, parameterIndex);
- }
- }
-
- private static void DecodeMarshalAsComInterface(string[] paramNames, object?[] values, UnmanagedType unmanagedType, MarshallingInfo info)
- {
- int? parameterIndex = null;
- for (int i = 0; i < paramNames.Length; i++)
- {
- if (paramNames[i] == "IidParameterIndex")
- {
- parameterIndex = (int?)values[i];
- break;
- }
- }
- info.SetMarshalAsComInterface(unmanagedType, parameterIndex);
- }
-
- private static void DecodeMarshalAsCustom(string[] paramNames, object?[] values, MarshallingInfo info)
- {
- string? cookie = null;
- Type? type = null;
- string? name = null;
- for (int i = 0; i < paramNames.Length; i++)
- {
- switch (paramNames[i])
- {
- case "MarshalType":
- name = (string?)values[i];
- break;
- case "MarshalTypeRef":
- type = (Type?)values[i];
- break;
- case "MarshalCookie":
- cookie = (string?)values[i];
- break;
- // other parameters ignored with no error
- }
- }
-
- info.SetMarshalAsCustom((object?)name ?? type!, cookie);
- }
- }
}
}
diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs
index 4f45898d62890d..99cdaceeb9f8cf 100644
--- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs
+++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/MethodBuilderImpl.cs
@@ -3,6 +3,7 @@
using System.Buffers.Binary;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection.Metadata;
@@ -23,6 +24,7 @@ internal sealed class MethodBuilderImpl : MethodBuilder
internal DllImportData? _dllImportData;
internal List? _customAttributes;
+ internal ParameterBuilderImpl[]? _parameters;
internal MethodBuilderImpl(string name, MethodAttributes attributes, CallingConventions callingConventions, Type? returnType,
Type[]? parameterTypes, ModuleBuilderImpl module, TypeBuilderImpl declaringType)
@@ -37,6 +39,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
for (int i = 0; i < parameterTypes.Length; i++)
{
ArgumentNullException.ThrowIfNull(_parameterTypes[i] = parameterTypes[i], nameof(parameterTypes));
@@ -51,7 +54,18 @@ internal BlobBuilder GetMethodSignatureBlob() =>
protected override bool InitLocalsCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
protected override GenericTypeParameterBuilder[] DefineGenericParametersCore(params string[] names) => throw new NotImplementedException();
- protected override ParameterBuilder DefineParameterCore(int position, ParameterAttributes attributes, string? strParamName) => throw new NotImplementedException();
+ protected override ParameterBuilder DefineParameterCore(int position, ParameterAttributes attributes, string? strParamName)
+ {
+ if (position > 0 && (_parameterTypes == null || position > _parameterTypes.Length))
+ throw new ArgumentOutOfRangeException(SR.ArgumentOutOfRange_ParamSequence);
+
+ _parameters ??= new ParameterBuilderImpl[1];
+
+ attributes &= ~ParameterAttributes.ReservedMask;
+ ParameterBuilderImpl parameter = new ParameterBuilderImpl(this, position, attributes, strParamName);
+ _parameters[position] = parameter;
+ return parameter;
+ }
protected override ILGenerator GetILGeneratorCore(int size) => throw new NotImplementedException();
protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute)
{
@@ -142,103 +156,4 @@ public override object Invoke(object? obj, BindingFlags invokeAttr, Binder? bind
public override MethodInfo MakeGenericMethod(params System.Type[] typeArguments)
=> throw new NotImplementedException();
}
-
- internal sealed class DllImportData
- {
- private readonly string _moduleName;
- private readonly string? _entryPoint;
- private readonly MethodImportAttributes _flags;
- internal DllImportData(string moduleName, string? entryPoint, MethodImportAttributes flags)
- {
- _moduleName = moduleName;
- _entryPoint = entryPoint;
- _flags = flags;
- }
-
- public string ModuleName => _moduleName;
-
- public string? EntryPoint => _entryPoint;
-
- public MethodImportAttributes Flags => _flags;
-
- internal static DllImportData CreateDllImportData(CustomAttributeInfo attr, out bool preserveSig)
- {
- string? moduleName = (string?)attr._ctorArgs[0];
- if (moduleName == null || moduleName.Length == 0)
- {
- throw new ArgumentException(SR.Argument_DllNameCannotBeEmpty);
- }
-
- MethodImportAttributes importAttributes = MethodImportAttributes.None;
- string? entryPoint = null;
- preserveSig = true;
- for (int i = 0; i < attr._namedParamNames.Length; ++i)
- {
- string name = attr._namedParamNames[i];
- object value = attr._namedParamValues[i]!;
- switch (name)
- {
- case "PreserveSig":
- preserveSig = (bool)value;
- break;
- case "CallingConvention":
- importAttributes |= (CallingConvention)value switch
- {
- CallingConvention.Cdecl => MethodImportAttributes.CallingConventionCDecl,
- CallingConvention.FastCall => MethodImportAttributes.CallingConventionFastCall,
- CallingConvention.StdCall => MethodImportAttributes.CallingConventionStdCall,
- CallingConvention.ThisCall => MethodImportAttributes.CallingConventionThisCall,
- _=> MethodImportAttributes.CallingConventionWinApi // Roslyn defaults with this
- };
- break;
- case "CharSet":
- importAttributes |= (CharSet)value switch
- {
- CharSet.Ansi => MethodImportAttributes.CharSetAnsi,
- CharSet.Auto => MethodImportAttributes.CharSetAuto,
- CharSet.Unicode => MethodImportAttributes.CharSetUnicode,
- _ => MethodImportAttributes.CharSetAuto
- };
- break;
- case "EntryPoint":
- entryPoint = (string?)value;
- break;
- case "ExactSpelling":
- if ((bool)value)
- {
- importAttributes |= MethodImportAttributes.ExactSpelling;
- }
- break;
- case "SetLastError":
- if ((bool)value)
- {
- importAttributes |= MethodImportAttributes.SetLastError;
- }
- break;
- case "BestFitMapping":
- if ((bool)value)
- {
- importAttributes |= MethodImportAttributes.BestFitMappingEnable;
- }
- else
- {
- importAttributes |= MethodImportAttributes.BestFitMappingDisable;
- }
- break;
- case "ThrowOnUnmappableChar":
- if ((bool)value)
- {
- importAttributes |= MethodImportAttributes.ThrowOnUnmappableCharEnable;
- }
- else
- {
- importAttributes |= MethodImportAttributes.ThrowOnUnmappableCharDisable;
- }
- break;
- }
- }
-
- return new DllImportData(moduleName, entryPoint, importAttributes);
- }
- }
}
diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs
index 775a5f647a5328..f18aace4f14afe 100644
--- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs
+++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ModuleBuilderImpl.cs
@@ -24,6 +24,7 @@ internal sealed class ModuleBuilderImpl : ModuleBuilder
private int _nextTypeDefRowId = 1;
private int _nextMethodDefRowId = 1;
private int _nextFieldDefRowId = 1;
+ private int _nextParameterRowId = 1;
private bool _coreTypesFullyPopulated;
private Type?[]? _coreTypes;
private static readonly Type[] s_coreTypes = { typeof(void), typeof(object), typeof(bool), typeof(char), typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int),
@@ -133,10 +134,33 @@ internal void AppendMetadata()
foreach (MethodBuilderImpl method in typeBuilder._methodDefinitions)
{
- MethodDefinitionHandle methodHandle = AddMethodDefinition(method, method.GetMethodSignatureBlob());
+ MethodDefinitionHandle methodHandle = AddMethodDefinition(method, method.GetMethodSignatureBlob(), _nextParameterRowId);
WriteCustomAttributes(method._customAttributes, methodHandle);
_nextMethodDefRowId++;
+ if (method._parameters != null)
+ {
+ foreach (ParameterBuilderImpl parameter in method._parameters)
+ {
+ if (parameter != null)
+ {
+ ParameterHandle parameterHandle = AddParameter(parameter);
+ WriteCustomAttributes(parameter._customAttributes, parameterHandle);
+ _nextParameterRowId++;
+
+ if (parameter._marshallingData != null)
+ {
+ AddMarshalling(parameterHandle, parameter._marshallingData.SerializeMarshallingData());
+ }
+
+ if (parameter._defaultValue != DBNull.Value)
+ {
+ AddDefaultValue(parameterHandle, parameter._defaultValue);
+ }
+ }
+ }
+ }
+
if (method._dllImportData != null)
{
AddMethodImport(methodHandle, method._dllImportData.EntryPoint ?? method.Name,
@@ -155,9 +179,9 @@ internal void AppendMetadata()
AddFieldLayout(fieldHandle, field._offset);
}
- if (field._marshallingInfo != null)
+ if (field._marshallingData != null)
{
- AddFieldMarshalling(fieldHandle, field._marshallingInfo.PopulateMarshallingBlob(_metadataBuilder));
+ AddMarshalling(fieldHandle, field._marshallingData.SerializeMarshallingData());
}
}
}
@@ -223,6 +247,9 @@ private AssemblyReferenceHandle GetAssemblyReference(Assembly assembly)
return handle;
}
+ private void AddDefaultValue(ParameterHandle parameterHandle, object? defaultValue) =>
+ _metadataBuilder.AddConstant(parameterHandle, defaultValue);
+
private FieldDefinitionHandle AddFieldDefinition(FieldBuilderImpl field, BlobBuilder fieldSignature) =>
_metadataBuilder.AddFieldDefinition(
attributes: field.Attributes,
@@ -238,14 +265,14 @@ private TypeDefinitionHandle AddTypeDefinition(TypeBuilderImpl type, EntityHandl
fieldList: MetadataTokens.FieldDefinitionHandle(fieldToken),
methodList: MetadataTokens.MethodDefinitionHandle(methodToken));
- private MethodDefinitionHandle AddMethodDefinition(MethodBuilderImpl method, BlobBuilder methodSignature) =>
+ private MethodDefinitionHandle AddMethodDefinition(MethodBuilderImpl method, BlobBuilder methodSignature, int parameterToken) =>
_metadataBuilder.AddMethodDefinition(
attributes: method.Attributes,
implAttributes: method.GetMethodImplementationFlags(),
name: _metadataBuilder.GetOrAddString(method.Name),
signature: _metadataBuilder.GetOrAddBlob(methodSignature),
bodyOffset: -1, // No body supported yet
- parameterList: MetadataTokens.ParameterHandle(1));
+ parameterList: MetadataTokens.ParameterHandle(parameterToken));
private TypeReferenceHandle AddTypeReference(Type type, AssemblyReferenceHandle parent) =>
_metadataBuilder.AddTypeReference(
@@ -276,10 +303,14 @@ private ModuleReferenceHandle AddModuleReference(string moduleName) =>
private void AddFieldLayout(FieldDefinitionHandle fieldHandle, int offset) =>
_metadataBuilder.AddFieldLayout(field: fieldHandle, offset: offset);
- private void AddFieldMarshalling(FieldDefinitionHandle fieldHandle, BlobHandle descriptor)
- {
- _metadataBuilder.AddMarshallingDescriptor(fieldHandle, descriptor);
- }
+ private void AddMarshalling(EntityHandle fieldHandle, BlobBuilder builder) =>
+ _metadataBuilder.AddMarshallingDescriptor(fieldHandle, _metadataBuilder.GetOrAddBlob(builder));
+
+ private ParameterHandle AddParameter(ParameterBuilderImpl parameter) =>
+ _metadataBuilder.AddParameter(
+ attributes: (ParameterAttributes)parameter.Attributes,
+ name: parameter.Name != null ? _metadataBuilder.GetOrAddString(parameter.Name) : default,
+ sequenceNumber: parameter.Position);
private AssemblyReferenceHandle AddAssemblyReference(string name, Version? version, string? culture,
byte[]? publicKeyToken, AssemblyNameFlags flags, AssemblyContentType contentType) =>
diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ParameterBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ParameterBuilderImpl.cs
new file mode 100644
index 00000000000000..4d64a644ab47e9
--- /dev/null
+++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/ParameterBuilderImpl.cs
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+
+namespace System.Reflection.Emit
+{
+ internal sealed class ParameterBuilderImpl : ParameterBuilder
+ {
+ private readonly string? _name;
+ private readonly int _position;
+ private readonly MethodBuilderImpl _methodBuilder;
+ private ParameterAttributes _attributes;
+
+ internal List? _customAttributes;
+ internal MarshallingData? _marshallingData;
+ internal object? _defaultValue = DBNull.Value;
+
+ public ParameterBuilderImpl(MethodBuilderImpl methodBuilder, int sequence, ParameterAttributes attributes, string? paramName)
+ {
+ _position = sequence;
+ _name = paramName;
+ _methodBuilder = methodBuilder;
+ _attributes = attributes;
+ }
+
+ public override int Attributes => (int)_attributes;
+
+ public override string? Name => _name;
+
+ public override int Position => _position;
+
+ public override void SetConstant(object? defaultValue) => _defaultValue = defaultValue;
+
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute)
+ {
+ switch (con.ReflectedType!.FullName)
+ {
+ case "System.Runtime.InteropServices.InAttribute":
+ _attributes |= ParameterAttributes.In;
+ return;
+ case "System.Runtime.InteropServices.OutAttribute":
+ _attributes |= ParameterAttributes.Out;
+ return;
+ case "System.Runtime.InteropServices.OptionalAttribute":
+ _attributes |= ParameterAttributes.Optional;
+ return;
+ case "System.Runtime.InteropServices.MarshalAsAttribute":
+ _attributes |= ParameterAttributes.HasFieldMarshal;
+ _marshallingData = MarshallingData.CreateMarshallingData(con, binaryAttribute, isField: false);
+ return;
+ case "System.Runtime.InteropServices.DefaultParameterValueAttribute":
+ // MS.NET doesn't handle this attribute but we handle it for consistency TODO: not sure if we need to handle this
+ CustomAttributeInfo caInfo = CustomAttributeInfo.DecodeCustomAttribute(con, binaryAttribute);
+ SetConstant(caInfo._ctorArgs[0]);
+ return;
+ }
+
+ _customAttributes ??= new List();
+ _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute));
+ }
+ }
+}
diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/PseudoCustomAttributesData.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/PseudoCustomAttributesData.cs
new file mode 100644
index 00000000000000..93dd864ccedf10
--- /dev/null
+++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/PseudoCustomAttributesData.cs
@@ -0,0 +1,495 @@
+// 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;
+using System.Reflection.Metadata;
+using System.Runtime.InteropServices;
+
+namespace System.Reflection.Emit
+{
+ internal sealed class DllImportData
+ {
+ private readonly string _moduleName;
+ private readonly string? _entryPoint;
+ private readonly MethodImportAttributes _flags;
+
+ internal DllImportData(string moduleName, string? entryPoint, MethodImportAttributes flags)
+ {
+ _moduleName = moduleName;
+ _entryPoint = entryPoint;
+ _flags = flags;
+ }
+
+ public string ModuleName => _moduleName;
+
+ public string? EntryPoint => _entryPoint;
+
+ public MethodImportAttributes Flags => _flags;
+
+ internal static DllImportData CreateDllImportData(CustomAttributeInfo attr, out bool preserveSig)
+ {
+ string? moduleName = (string?)attr._ctorArgs[0];
+ if (moduleName == null || moduleName.Length == 0)
+ {
+ throw new ArgumentException(SR.Argument_DllNameCannotBeEmpty);
+ }
+
+ MethodImportAttributes importAttributes = MethodImportAttributes.None;
+ string? entryPoint = null;
+ preserveSig = true;
+ for (int i = 0; i < attr._namedParamNames.Length; ++i)
+ {
+ string name = attr._namedParamNames[i];
+ object value = attr._namedParamValues[i]!;
+ switch (name)
+ {
+ case "PreserveSig":
+ preserveSig = (bool)value;
+ break;
+ case "CallingConvention":
+ importAttributes |= (CallingConvention)value switch
+ {
+ CallingConvention.Cdecl => MethodImportAttributes.CallingConventionCDecl,
+ CallingConvention.FastCall => MethodImportAttributes.CallingConventionFastCall,
+ CallingConvention.StdCall => MethodImportAttributes.CallingConventionStdCall,
+ CallingConvention.ThisCall => MethodImportAttributes.CallingConventionThisCall,
+ _ => MethodImportAttributes.CallingConventionWinApi // Roslyn defaults with this
+ };
+ break;
+ case "CharSet":
+ importAttributes |= (CharSet)value switch
+ {
+ CharSet.Ansi => MethodImportAttributes.CharSetAnsi,
+ CharSet.Auto => MethodImportAttributes.CharSetAuto,
+ CharSet.Unicode => MethodImportAttributes.CharSetUnicode,
+ _ => MethodImportAttributes.CharSetAuto
+ };
+ break;
+ case "EntryPoint":
+ entryPoint = (string?)value;
+ break;
+ case "ExactSpelling":
+ if ((bool)value)
+ {
+ importAttributes |= MethodImportAttributes.ExactSpelling;
+ }
+ break;
+ case "SetLastError":
+ if ((bool)value)
+ {
+ importAttributes |= MethodImportAttributes.SetLastError;
+ }
+ break;
+ case "BestFitMapping":
+ if ((bool)value)
+ {
+ importAttributes |= MethodImportAttributes.BestFitMappingEnable;
+ }
+ else
+ {
+ importAttributes |= MethodImportAttributes.BestFitMappingDisable;
+ }
+ break;
+ case "ThrowOnUnmappableChar":
+ if ((bool)value)
+ {
+ importAttributes |= MethodImportAttributes.ThrowOnUnmappableCharEnable;
+ }
+ else
+ {
+ importAttributes |= MethodImportAttributes.ThrowOnUnmappableCharDisable;
+ }
+ break;
+ }
+ }
+
+ return new DllImportData(moduleName, entryPoint, importAttributes);
+ }
+ }
+
+ internal sealed class MarshallingData
+ {
+ private UnmanagedType _marshalType;
+ private int _marshalArrayElementType; // safe array: VarEnum; array: UnmanagedType
+ private int _marshalArrayElementCount; // number of elements in an array, length of a string, or Unspecified
+ private int _marshalParameterIndex; // index of parameter that specifies array size (short) or IID (int), or Unspecified
+ private object? _marshalTypeNameOrSymbol; // custom marshaller: string or Type; safe array: element type
+ private string? _marshalCookie;
+
+ internal const int Invalid = -1;
+ private const UnmanagedType InvalidUnmanagedType = (UnmanagedType)Invalid;
+ private const VarEnum InvalidVariantType = (VarEnum)Invalid;
+ private const int MaxMarshalInteger = 0x1fffffff;
+
+ // The logic imported from https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs#L3543
+ internal BlobBuilder SerializeMarshallingData()
+ {
+ BlobBuilder writer = new BlobBuilder(); ;
+ writer.WriteCompressedInteger((int)_marshalType);
+ switch (_marshalType)
+ {
+ case UnmanagedType.ByValArray: // NATIVE_TYPE_FIXEDARRAY
+ Debug.Assert(_marshalArrayElementCount >= 0);
+ writer.WriteCompressedInteger(_marshalArrayElementCount);
+ if (_marshalArrayElementType >= 0)
+ {
+ writer.WriteCompressedInteger(_marshalArrayElementType);
+ }
+ break;
+ case UnmanagedType.CustomMarshaler:
+ writer.WriteUInt16(0); // padding
+
+ switch (_marshalTypeNameOrSymbol)
+ {
+ case Type type:
+ writer.WriteSerializedString(type.FullName); // or AssemblyQualifiedName?
+ break;
+ case null:
+ writer.WriteByte(0);
+ break;
+ default:
+ writer.WriteSerializedString((string)_marshalTypeNameOrSymbol);
+ break;
+ }
+
+ if (_marshalCookie != null)
+ {
+ writer.WriteSerializedString(_marshalCookie);
+ }
+ else
+ {
+ writer.WriteByte(0);
+ }
+ break;
+ case UnmanagedType.LPArray: // NATIVE_TYPE_ARRAY
+ Debug.Assert(_marshalArrayElementType >= 0);
+ writer.WriteCompressedInteger(_marshalArrayElementType);
+ if (_marshalParameterIndex >= 0)
+ {
+ writer.WriteCompressedInteger(_marshalParameterIndex);
+ if (_marshalArrayElementCount >= 0)
+ {
+ writer.WriteCompressedInteger(_marshalArrayElementCount);
+ writer.WriteByte(1); // The parameter number is valid
+ }
+ }
+ else if (_marshalArrayElementCount >= 0)
+ {
+ writer.WriteByte(0); // Dummy parameter value emitted so that NumberOfElements can be in a known position
+ writer.WriteCompressedInteger(_marshalArrayElementCount);
+ writer.WriteByte(0); // The parameter number is not valid
+ }
+ break;
+ case UnmanagedType.SafeArray:
+ VarEnum safeArrayElementSubtype = (VarEnum)_marshalArrayElementType;
+ if (safeArrayElementSubtype >= 0)
+ {
+ writer.WriteCompressedInteger((int)safeArrayElementSubtype);
+
+ if (_marshalTypeNameOrSymbol is Type elementType)
+ {
+ writer.WriteSerializedString(elementType.FullName);
+ }
+ }
+ break;
+ case UnmanagedType.ByValTStr: // NATIVE_TYPE_FIXEDSYSSTRING
+ writer.WriteCompressedInteger(_marshalArrayElementCount);
+ break;
+
+ case UnmanagedType.Interface:
+ case UnmanagedType.IDispatch:
+ case UnmanagedType.IUnknown:
+ if (_marshalParameterIndex >= 0)
+ {
+ writer.WriteCompressedInteger(_marshalParameterIndex);
+ }
+ break;
+ }
+
+ return writer;
+ }
+
+ internal void SetMarshalAsCustom(object typeSymbolOrName, string? cookie)
+ {
+ _marshalType = UnmanagedType.CustomMarshaler;
+ _marshalTypeNameOrSymbol = typeSymbolOrName;
+ _marshalCookie = cookie;
+ }
+
+ internal void SetMarshalAsComInterface(UnmanagedType unmanagedType, int? parameterIndex)
+ {
+ Debug.Assert(parameterIndex == null || parameterIndex >= 0 && parameterIndex <= MaxMarshalInteger);
+
+ _marshalType = unmanagedType;
+ _marshalParameterIndex = parameterIndex ?? Invalid;
+ }
+
+ internal void SetMarshalAsArray(UnmanagedType? elementType, int? elementCount, short? parameterIndex)
+ {
+ Debug.Assert(elementCount == null || elementCount >= 0 && elementCount <= MaxMarshalInteger);
+ Debug.Assert(parameterIndex == null || parameterIndex >= 0);
+
+ _marshalType = UnmanagedType.LPArray;
+ _marshalArrayElementType = (int)(elementType ?? (UnmanagedType)0x50);
+ _marshalArrayElementCount = elementCount ?? Invalid;
+ _marshalParameterIndex = parameterIndex ?? Invalid;
+ }
+
+ internal void SetMarshalAsFixedArray(UnmanagedType? elementType, int? elementCount)
+ {
+ Debug.Assert(elementCount == null || elementCount >= 0 && elementCount <= MaxMarshalInteger);
+ Debug.Assert(elementType == null || elementType >= 0 && (int)elementType <= MaxMarshalInteger);
+
+ _marshalType = UnmanagedType.ByValArray;
+ _marshalArrayElementType = (int)(elementType ?? InvalidUnmanagedType);
+ _marshalArrayElementCount = elementCount ?? Invalid;
+ }
+
+ internal void SetMarshalAsSafeArray(VarEnum? elementType, Type? type)
+ {
+ Debug.Assert(elementType == null || elementType >= 0 && (int)elementType <= MaxMarshalInteger);
+
+ _marshalType = UnmanagedType.SafeArray;
+ _marshalArrayElementType = (int)(elementType ?? InvalidVariantType);
+ _marshalTypeNameOrSymbol = type;
+ }
+
+ internal void SetMarshalAsFixedString(int elementCount)
+ {
+ Debug.Assert(elementCount >= 0 && elementCount <= MaxMarshalInteger);
+
+ _marshalType = UnmanagedType.ByValTStr;
+ _marshalArrayElementCount = elementCount;
+ }
+
+ internal void SetMarshalAsSimpleType(UnmanagedType type)
+ {
+ Debug.Assert(type >= 0 && (int)type <= MaxMarshalInteger);
+ _marshalType = type;
+ }
+
+ // The logic imported from https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/Symbols/Attributes/MarshalAsAttributeDecoder.cs
+ internal static MarshallingData CreateMarshallingData(ConstructorInfo con, ReadOnlySpan binaryAttribute, bool isField)
+ {
+ CustomAttributeInfo attributeInfo = CustomAttributeInfo.DecodeCustomAttribute(con, binaryAttribute);
+ MarshallingData info = new();
+ UnmanagedType unmanagedType;
+
+ if (attributeInfo._ctorArgs[0] is short shortValue)
+ {
+ unmanagedType = (UnmanagedType)shortValue;
+ }
+ else
+ {
+ unmanagedType = (UnmanagedType)attributeInfo._ctorArgs[0]!;
+ }
+
+ switch (unmanagedType)
+ {
+ case UnmanagedType.CustomMarshaler:
+ DecodeMarshalAsCustom(attributeInfo._namedParamNames, attributeInfo._namedParamValues, info);
+ break;
+ case UnmanagedType.Interface:
+ case UnmanagedType.IDispatch:
+ case UnmanagedType.IUnknown:
+ DecodeMarshalAsComInterface(attributeInfo._namedParamNames, attributeInfo._namedParamValues, unmanagedType, info);
+ break;
+ case UnmanagedType.LPArray:
+ DecodeMarshalAsArray(attributeInfo._namedParamNames, attributeInfo._namedParamValues, isFixed: false, info);
+ break;
+ case UnmanagedType.ByValArray:
+ if (!isField)
+ {
+ throw new NotSupportedException(SR.Format(SR.NotSupported_UnmanagedTypeOnlyForFields, nameof(UnmanagedType.ByValArray)));
+ }
+ DecodeMarshalAsArray(attributeInfo._namedParamNames, attributeInfo._namedParamValues, isFixed: true, info);
+ break;
+ case UnmanagedType.SafeArray:
+ DecodeMarshalAsSafeArray(attributeInfo._namedParamNames, attributeInfo._namedParamValues, info);
+ break;
+ case UnmanagedType.ByValTStr:
+ if (!isField)
+ {
+ throw new NotSupportedException(SR.Format(SR.NotSupported_UnmanagedTypeOnlyForFields, nameof(UnmanagedType.ByValArray)));
+ }
+ DecodeMarshalAsFixedString(attributeInfo._namedParamNames, attributeInfo._namedParamValues, info);
+ break;
+#pragma warning disable CS0618 // Type or member is obsolete
+ case UnmanagedType.VBByRefStr:
+#pragma warning restore CS0618
+ // named parameters ignored with no error
+ info.SetMarshalAsSimpleType(unmanagedType);
+ break;
+ default:
+ if ((int)unmanagedType < 0 || (int)unmanagedType > MaxMarshalInteger)
+ {
+ throw new ArgumentException(SR.Argument_InvalidArgumentForAttribute, nameof(con));
+ }
+ else
+ {
+ // named parameters ignored with no error
+ info.SetMarshalAsSimpleType(unmanagedType);
+ }
+ break;
+ }
+
+ return info;
+ }
+
+ private static void DecodeMarshalAsFixedString(string[] paramNames, object?[] values, MarshallingData info)
+ {
+ int elementCount = -1;
+
+ for (int i = 0; i < paramNames.Length; i++)
+ {
+ switch (paramNames[i])
+ {
+ case "SizeConst":
+ elementCount = (int)values[i]!;
+ break;
+ case "ArraySubType":
+ case "SizeParamIndex":
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidParameterForUnmanagedType, paramNames[i], "ByValTStr"), "binaryAttribute");
+ // other parameters ignored with no error
+ }
+ }
+
+ if (elementCount < 0)
+ {
+ // SizeConst must be specified:
+ throw new ArgumentException(SR.Argument_SizeConstMustBeSpecified, "binaryAttribute");
+ }
+
+ info.SetMarshalAsFixedString(elementCount);
+ }
+
+ private static void DecodeMarshalAsSafeArray(string[] paramNames, object?[] values, MarshallingData info)
+ {
+ VarEnum? elementTypeVariant = null;
+ Type? elementType = null;
+ int symbolIndex = -1;
+
+ for (int i = 0; i < paramNames.Length; i++)
+ {
+ switch (paramNames[i])
+ {
+ case "SafeArraySubType":
+ elementTypeVariant = (VarEnum)values[i]!;
+ break;
+ case "SafeArrayUserDefinedSubType":
+ elementType = (Type?)values[i];
+ symbolIndex = i;
+ break;
+ case "ArraySubType":
+ case "SizeConst":
+ case "SizeParamIndex":
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidParameterForUnmanagedType, paramNames[i], "SafeArray"), "binaryAttribute");
+ // other parameters ignored with no error
+ }
+ }
+
+ switch (elementTypeVariant)
+ {
+ case VarEnum.VT_DISPATCH:
+ case VarEnum.VT_UNKNOWN:
+ case VarEnum.VT_RECORD:
+ // only these variants accept specification of user defined subtype
+ break;
+
+ default:
+ if (elementTypeVariant != null && symbolIndex >= 0)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidParameterForUnmanagedType, elementType, "SafeArray"), "binaryAttribute");
+ }
+ else
+ {
+ // type ignored:
+ elementType = null;
+ }
+ break;
+ }
+
+ info.SetMarshalAsSafeArray(elementTypeVariant, elementType);
+ }
+
+ private static void DecodeMarshalAsArray(string[] paramNames, object?[] values, bool isFixed, MarshallingData info)
+ {
+ UnmanagedType? elementType = null;
+ int? elementCount = isFixed ? 1 : null;
+ short? parameterIndex = null;
+
+ for (int i = 0; i < paramNames.Length; i++)
+ {
+ switch (paramNames[i])
+ {
+ case "ArraySubType":
+ elementType = (UnmanagedType)values[i]!;
+ break;
+ case "SizeConst":
+ elementCount = (int?)values[i];
+ break;
+ case "SizeParamIndex":
+ if (isFixed)
+ {
+ goto case "SafeArraySubType";
+ }
+ parameterIndex = (short?)values[i];
+ break;
+ case "SafeArraySubType":
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidParameterForUnmanagedType,
+ paramNames[i], isFixed ? "ByValArray" : "LPArray"), "binaryAttribute");
+ // other parameters ignored with no error
+ }
+ }
+
+ if (isFixed)
+ {
+ info.SetMarshalAsFixedArray(elementType, elementCount);
+ }
+ else
+ {
+ info.SetMarshalAsArray(elementType, elementCount, parameterIndex);
+ }
+ }
+
+ private static void DecodeMarshalAsComInterface(string[] paramNames, object?[] values, UnmanagedType unmanagedType, MarshallingData info)
+ {
+ int? parameterIndex = null;
+ for (int i = 0; i < paramNames.Length; i++)
+ {
+ if (paramNames[i] == "IidParameterIndex")
+ {
+ parameterIndex = (int?)values[i];
+ break;
+ }
+ }
+
+ info.SetMarshalAsComInterface(unmanagedType, parameterIndex);
+ }
+
+ private static void DecodeMarshalAsCustom(string[] paramNames, object?[] values, MarshallingData info)
+ {
+ string? cookie = null;
+ Type? type = null;
+ string? name = null;
+ for (int i = 0; i < paramNames.Length; i++)
+ {
+ switch (paramNames[i])
+ {
+ case "MarshalType":
+ name = (string?)values[i];
+ break;
+ case "MarshalTypeRef":
+ type = (Type?)values[i];
+ break;
+ case "MarshalCookie":
+ cookie = (string?)values[i];
+ break;
+ // other parameters ignored with no error
+ }
+ }
+
+ info.SetMarshalAsCustom((object?)name ?? type!, cookie);
+ }
+ }
+}
diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveCustomAttributeTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveCustomAttributeTests.cs
index 0f1d3c929b3e36..79b9e77bfdf140 100644
--- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveCustomAttributeTests.cs
+++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveCustomAttributeTests.cs
@@ -138,7 +138,7 @@ private static void PopulateMembersForModule(ModuleBuilder mb, Type[] types, Lis
TypeBuilder tb = mb.DefineType(type.FullName, type.Attributes, type.BaseType);
typeAttributes.ForEach(tb.SetCustomAttribute);
- DefineMethodsAndSetAttributes(methodAttributes, tb, type.IsInterface ? type.GetMethods() : type.GetMethods(BindingFlags.DeclaredOnly));
+ DefineMethodsAndSetAttributes(methodAttributes, tb, type.IsInterface ? type.GetMethods() : type.GetMethods(BindingFlags.DeclaredOnly), methodAttributes);
DefineFieldsAndSetAttributes(fieldAttributes, type.GetFields(), tb);
}
}
@@ -152,12 +152,23 @@ private static void DefineFieldsAndSetAttributes(List? f
}
}
- private static void DefineMethodsAndSetAttributes(List methodAttributes, TypeBuilder tb, MethodInfo[] methods)
+ private static void DefineMethodsAndSetAttributes(List methodAttributes, TypeBuilder tb, MethodInfo[] methods, List paramAttributes)
{
foreach (var method in methods)
{
- MethodBuilder meb = tb.DefineMethod(method.Name, method.Attributes, method.CallingConvention, method.ReturnType, null);
+ ParameterInfo[] parameters = method.GetParameters();
+ MethodBuilder meb = tb.DefineMethod(method.Name, method.Attributes, method.CallingConvention, method.ReturnType, parameters.Select(p => p.ParameterType).ToArray());
methodAttributes.ForEach(meb.SetCustomAttribute);
+
+ foreach (ParameterInfo param in parameters)
+ {
+ ParameterBuilder pb = meb.DefineParameter(param.Position + 1, param.Attributes, param.Name);
+ paramAttributes.ForEach(pb.SetCustomAttribute);
+ if (param.ParameterType.Equals(typeof(string)))
+ {
+ pb.SetConstant("Hello");
+ }
+ }
}
}
@@ -247,26 +258,32 @@ public void InterfacesWithPseudoCustomAttributes()
{
Type dllType = typeof(DllImportAttribute);
Type type = typeof(IMultipleMethod);
- List typeAttributes = new() { new CustomAttributeBuilder(typeof(ComImportAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
- new CustomAttributeBuilder(typeof(SuppressUnmanagedCodeSecurityAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
- new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args)
- };
- CustomAttributeBuilder[] methodAttributes = new[] { new CustomAttributeBuilder(typeof(PreserveSigAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
- new CustomAttributeBuilder(typeof(SuppressUnmanagedCodeSecurityAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
- new CustomAttributeBuilder(typeof(SpecialNameAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
- new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args),
- new CustomAttributeBuilder(typeof(MethodImplAttribute).GetConstructor(new Type[] { typeof(MethodImplOptions) }),
- new object[] { MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization }),
- new CustomAttributeBuilder(dllType.GetConstructor(new Type[] { typeof(string) }), new object[] { "test.dll" },
- new FieldInfo[] { dllType.GetField("CharSet"), dllType.GetField("SetLastError"), dllType.GetField("CallingConvention"), dllType.GetField("BestFitMapping"),
- dllType.GetField("ThrowOnUnmappableChar") }, new object[]{ CharSet.Ansi, true, CallingConvention.FastCall, true, false }),
- };
-
- AssemblyBuilder ab = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(
- PopulateAssemblyName(), null, typeof(string), out MethodInfo saveMethod);
+ List typeAttributes = new() {
+ new CustomAttributeBuilder(typeof(ComImportAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(typeof(SuppressUnmanagedCodeSecurityAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args)};
+ List methodAttributes = new() {
+ new CustomAttributeBuilder(typeof(PreserveSigAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(typeof(SuppressUnmanagedCodeSecurityAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(typeof(SpecialNameAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args),
+ new CustomAttributeBuilder(typeof(MethodImplAttribute).GetConstructor(new Type[] { typeof(MethodImplOptions) }),
+ new object[] { MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization }),
+ new CustomAttributeBuilder(dllType.GetConstructor(new Type[] { typeof(string) }), new object[] { "test.dll" }, new FieldInfo[]
+ { dllType.GetField("CharSet"), dllType.GetField("SetLastError"), dllType.GetField("CallingConvention"), dllType.GetField("BestFitMapping"),
+ dllType.GetField("ThrowOnUnmappableChar") }, new object[]{ CharSet.Ansi, true, CallingConvention.FastCall, true, false })};
+ List parameterAttributes = new() {
+ new CustomAttributeBuilder(typeof(InAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(typeof(OutAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(typeof(OptionalAttribute).GetConstructor(Type.EmptyTypes), new object[] { }),
+ new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args),
+ new CustomAttributeBuilder(marshalAsEnumCtor, new object[] { UnmanagedType.CustomMarshaler },
+ new FieldInfo[] { typeof(MarshalAsAttribute).GetField("MarshalType")}, new object[] { typeof(EmptyTestClass).AssemblyQualifiedName })};
+
+ AssemblyBuilder ab = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(PopulateAssemblyName(), null, typeof(string), out MethodInfo saveMethod);
TypeBuilder tb = ab.DefineDynamicModule("Module").DefineType(type.FullName, type.Attributes);
typeAttributes.ForEach(tb.SetCustomAttribute);
- DefineMethodsAndSetAttributes(methodAttributes.ToList(), tb, type.GetMethods());
+ DefineMethodsAndSetAttributes(methodAttributes, tb, type.GetMethods(), parameterAttributes);
saveMethod.Invoke(ab, new object[] { file.Path });
Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path);
@@ -302,7 +319,7 @@ public void InterfacesWithPseudoCustomAttributes()
Assert.True((methodImpl & MethodImplAttributes.NoInlining) != 0); // MethodImplAttribute
Assert.True((methodImpl & MethodImplAttributes.AggressiveOptimization) != 0); // MethodImplAttribute
Assert.True((methodImpl & MethodImplAttributes.PreserveSig) != 0); // PreserveSigAttribute
- Assert.Equal(methodAttributes.Length - 2, methodAttributesFromDisk.Count);
+ Assert.Equal(methodAttributes.Count - 2, methodAttributesFromDisk.Count);
for (int i = 0; i < methodAttributesFromDisk.Count; i++)
{
@@ -347,6 +364,44 @@ public void InterfacesWithPseudoCustomAttributes()
break;
}
}
+
+ foreach(ParameterInfo param in method.GetParameters())
+ {
+ IList paramAttributes = param.GetCustomAttributesData();
+
+ Assert.Equal(5, paramAttributes.Count);
+ Assert.True((param.Attributes & ParameterAttributes.In) != 0); // InAttribute
+ Assert.True((param.Attributes & ParameterAttributes.Out) != 0); // OutAttribute
+ Assert.True((param.Attributes & ParameterAttributes.Optional) != 0); // OptionalAttribute
+ Assert.True((param.Attributes & ParameterAttributes.HasFieldMarshal) != 0); // MarshalAsAttribute
+
+ if (param.ParameterType.Equals(typeof(string)))
+ {
+ Assert.Equal("Hello", param.DefaultValue);
+ }
+
+ for (int i = 0; i < paramAttributes.Count; i++)
+ {
+ switch (paramAttributes[i].AttributeType.Name)
+ {
+ case "InAttribute":
+ case "OutAttribute":
+ case "OptionalAttribute":
+ break;
+ case "MarshalAsAttribute":
+ Assert.Equal(UnmanagedType.CustomMarshaler, (UnmanagedType)paramAttributes[i].ConstructorArguments[0].Value);
+ Assert.Equal(typeof(EmptyTestClass).AssemblyQualifiedName,
+ paramAttributes[i].NamedArguments.First(na => na.MemberName == "MarshalType").TypedValue.Value);
+ break;
+ case "GuidAttribute":
+ Assert.Equal(s_guidPair.args[0], paramAttributes[i].ConstructorArguments[0].Value);
+ break;
+ default:
+ Assert.Fail($"Not expected attribute : {paramAttributes[i].AttributeType.Name}");
+ break;
+ }
+ }
+ }
}
}
}
diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveWithVariousMembersTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveWithVariousMembersTests.cs
index bf256d909eb847..df89812f1c62db 100644
--- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveWithVariousMembersTests.cs
+++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveWithVariousMembersTests.cs
@@ -2,8 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
+using System.Runtime.InteropServices;
using Xunit;
namespace System.Reflection.Emit.Tests
@@ -129,21 +131,21 @@ public interface INoMethod
public interface IMultipleMethod
{
- string Func();
+ string Func(int a, string b);
IOneMethod MoreFunc();
- StructWithFields DoIExist();
+ StructWithFields DoIExist(int a, string b, bool c);
void BuildAPerpetualMotionMachine();
}
internal interface IAccess
{
- public Version BuildAI();
+ public Version BuildAI(double field);
public int DisableRogueAI();
}
public interface IOneMethod
{
- object Func();
+ object Func(string a, short b);
}
public struct EmptyStruct
diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblyTools.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblyTools.cs
index 0cb5fe311d37a2..4ec230e52bc8b1 100644
--- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblyTools.cs
+++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblyTools.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Runtime.InteropServices;
using Xunit;
@@ -30,7 +31,12 @@ private static void PopulateMembersForModule(ModuleBuilder mb, Type[] types)
MethodInfo[] methods = type.IsInterface ? type.GetMethods() : type.GetMethods(BindingFlags.DeclaredOnly);
foreach (var method in methods)
{
- MethodBuilder meb = tb.DefineMethod(method.Name, method.Attributes, method.CallingConvention, method.ReturnType, null);
+ ParameterInfo[] parameters = method.GetParameters();
+ MethodBuilder meb = tb.DefineMethod(method.Name, method.Attributes, method.CallingConvention, method.ReturnType, parameters.Select(p => p.ParameterType).ToArray());
+ foreach(ParameterInfo param in parameters)
+ {
+ meb.DefineParameter(param.Position + 1, param.Attributes, param.Name);
+ }
}
foreach (FieldInfo field in type.GetFields())
@@ -122,6 +128,20 @@ internal static void AssertMethods(MethodInfo[] sourceMethods, MethodInfo[] meth
Assert.Equal(sourceMethod.Name, methodFromDisk.Name);
Assert.Equal(sourceMethod.Attributes, methodFromDisk.Attributes);
Assert.Equal(sourceMethod.ReturnType.FullName, methodFromDisk.ReturnType.FullName);
+ AssertParameters(sourceMethod.GetParameters(), methodFromDisk.GetParameters());
+ }
+ }
+
+ private static void AssertParameters(ParameterInfo[] sourceParameters, ParameterInfo[] parametersLoaded)
+ {
+ Assert.Equal(sourceParameters.Length, parametersLoaded.Length);
+
+ for (int i = 0; i < sourceParameters.Length; i++)
+ {
+ Assert.Equal(sourceParameters[i].Name, parametersLoaded[i].Name);
+ Assert.Equal(sourceParameters[i].ParameterType.FullName, parametersLoaded[i].ParameterType.FullName);
+ Assert.Equal(sourceParameters[i].Attributes, parametersLoaded[i].Attributes);
+ Assert.Equal(sourceParameters[i].Position, parametersLoaded[i].Position);
}
}
}
diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
index 1cc7d38b44fb1c..a76cd02986ccac 100644
--- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -227,7 +227,6 @@
-
@@ -236,6 +235,7 @@
+
diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeConstructorBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeConstructorBuilder.Mono.cs
index 83c62a8e9817ac..ecfae6b04ab4bf 100644
--- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeConstructorBuilder.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeConstructorBuilder.Mono.cs
@@ -222,7 +222,7 @@ protected override ParameterBuilder DefineParameterCore(int iSequence, Parameter
if (type.is_created)
throw not_after_created();
- ParameterBuilder pb = new ParameterBuilder(this, iSequence, attributes, strParamName);
+ ParameterBuilder pb = new RuntimeParameterBuilder(this, iSequence, attributes, strParamName);
pinfo ??= new ParameterBuilder[parameters!.Length + 1];
pinfo[iSequence] = pb;
return pb;
diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeMethodBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeMethodBuilder.Mono.cs
index cdae1832367f8c..88996e06647a30 100644
--- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeMethodBuilder.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeMethodBuilder.Mono.cs
@@ -335,7 +335,7 @@ protected override ParameterBuilder DefineParameterCore(int position, ParameterA
if ((position < 0) || parameters == null || (position > parameters.Length))
throw new ArgumentOutOfRangeException(nameof(position));
- ParameterBuilder pb = new ParameterBuilder(this, position, attributes, strParamName);
+ ParameterBuilder pb = new RuntimeParameterBuilder(this, position, attributes, strParamName);
pinfo ??= new ParameterBuilder[parameters.Length + 1];
pinfo[position] = pb;
return pb;
diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeParameterBuilder.Mono.cs
similarity index 82%
rename from src/mono/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.Mono.cs
rename to src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeParameterBuilder.Mono.cs
index d634f330a21bb3..2f682a29d674aa 100644
--- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/ParameterBuilder.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeParameterBuilder.Mono.cs
@@ -41,7 +41,7 @@
namespace System.Reflection.Emit
{
[StructLayout(LayoutKind.Sequential)]
- public partial class ParameterBuilder
+ internal sealed class RuntimeParameterBuilder : ParameterBuilder
{
#region Sync with MonoReflectionParamBuilder in object-internals.h
private MethodBase methodb; /* MethodBuilder, ConstructorBuilder or DynamicMethod */
@@ -55,7 +55,7 @@ public partial class ParameterBuilder
#endregion
[DynamicDependency(nameof(def_value))] // Automatically keeps all previous fields too due to StructLayout
- internal ParameterBuilder(MethodBase mb, int pos, ParameterAttributes attributes, string? strParamName)
+ internal RuntimeParameterBuilder(MethodBase mb, int pos, ParameterAttributes attributes, string? strParamName)
{
name = strParamName;
position = pos;
@@ -67,32 +67,20 @@ internal ParameterBuilder(MethodBase mb, int pos, ParameterAttributes attributes
table_idx = mb.get_next_table_index(0x08, 1);
}
- public virtual int Attributes
+ public override int Attributes
{
get { return (int)attrs; }
}
- public bool IsIn
- {
- get { return ((int)attrs & (int)ParameterAttributes.In) != 0; }
- }
- public bool IsOut
- {
- get { return ((int)attrs & (int)ParameterAttributes.Out) != 0; }
- }
- public bool IsOptional
- {
- get { return ((int)attrs & (int)ParameterAttributes.Optional) != 0; }
- }
- public virtual string? Name
+ public override string? Name
{
get { return name; }
}
- public virtual int Position
+ public override int Position
{
get { return position; }
}
- public virtual void SetConstant(object? defaultValue)
+ public override void SetConstant(object? defaultValue)
{
if (position > 0)
{
@@ -104,9 +92,10 @@ public virtual void SetConstant(object? defaultValue)
attrs |= ParameterAttributes.HasDefault;
}
- public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute)
{
- string? attrname = customBuilder.Ctor.ReflectedType!.FullName;
+ CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute);
+ string? attrname = con.ReflectedType!.FullName;
if (attrname == "System.Runtime.InteropServices.InAttribute")
{
attrs |= ParameterAttributes.In;
@@ -151,11 +140,6 @@ public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
cattrs[0] = customBuilder;
}
}
-
- public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
- {
- SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
- }
}
}