diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs index b740d461df3f8e..842ebaf3c3c97d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs @@ -21,10 +21,14 @@ namespace System.Reflection.Emit { public class CustomAttributeBuilder { - internal readonly ConstructorInfo m_con; + private readonly ConstructorInfo m_con; private readonly object?[] m_constructorArgs; private readonly byte[] m_blob; + internal ConstructorInfo Ctor => m_con; + + internal byte[] Data => m_blob; + // public constructor to form the custom attribute with constructor and constructor // parameters. public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs) : diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs index b2d82487f02321..dd6c84158a01fe 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs @@ -288,7 +288,7 @@ public override Assembly GetSatelliteAssembly(CultureInfo culture, Version? vers /// /// Use this function if client decides to form the custom attribute blob themselves. /// - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { lock (SyncRoot) { @@ -299,16 +299,5 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binar binaryAttribute); } } - - /// - /// Use this function if client wishes to build CustomAttribute using CustomAttributeBuilder. - /// - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) - { - lock (SyncRoot) - { - customBuilder.CreateCustomAttribute(_manifestModuleBuilder, AssemblyDefToken); - } - } } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeConstructorBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeConstructorBuilder.cs index 86b20be8e7ff09..bb1c16bf4fe3c4 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeConstructorBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeConstructorBuilder.cs @@ -157,16 +157,11 @@ internal override Type GetReturnType() return m_methodBuilder.ReturnType; } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { m_methodBuilder.SetCustomAttribute(con, binaryAttribute); } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) - { - m_methodBuilder.SetCustomAttribute(customBuilder); - } - protected override void SetImplementationFlagsCore(MethodImplAttributes attributes) { m_methodBuilder.SetImplementationFlags(attributes); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEnumBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEnumBuilder.cs index 3e81b8ed9fc874..2e14270c0d0265 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEnumBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEnumBuilder.cs @@ -274,18 +274,11 @@ public override object[] GetCustomAttributes(Type attributeType, bool inherit) } // Use this function if client decides to form the custom attribute blob themselves - - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { m_typeBuilder.SetCustomAttribute(con, binaryAttribute); } - // Use this function if client wishes to build CustomAttribute using CustomAttributeBuilder - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) - { - m_typeBuilder.SetCustomAttribute(customBuilder); - } - // Return the class that declared this Field. public override Type? DeclaringType => m_typeBuilder.DeclaringType; @@ -293,7 +286,6 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil public override Type? ReflectedType => m_typeBuilder.ReflectedType; - // Returns true if one or more instance of attributeType is defined on this member. public override bool IsDefined(Type attributeType, bool inherit) { @@ -329,7 +321,6 @@ public override Type MakeArrayType(int rank) return SymbolType.FormCompoundType(s, this, 0)!; } - // Constructs a EnumBuilder. // EnumBuilder can only be a top-level (not nested) enum type. [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2064:UnrecognizedReflectionPattern", diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEventBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEventBuilder.cs index 41befaa64ce550..cf3da5e026c41a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEventBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEventBuilder.cs @@ -80,7 +80,7 @@ protected override void AddOtherMethodCore(MethodBuilder mdBuilder) // Use this function if client decides to form the custom attribute blob themselves - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { m_type.ThrowIfCreated(); @@ -91,13 +91,6 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binar binaryAttribute); } - // Use this function if client wishes to build CustomAttribute using CustomAttributeBuilder - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) - { - m_type.ThrowIfCreated(); - customBuilder.CreateCustomAttribute(m_module, m_evToken); - } - private readonly string m_name; // The name of the event private readonly int m_evToken; // The token of this event private readonly RuntimeModuleBuilder m_module; diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeFieldBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeFieldBuilder.cs index da3341e744410a..e607b1523d7653 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeFieldBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeFieldBuilder.cs @@ -150,7 +150,7 @@ protected override void SetConstantCore(object? defaultValue) RuntimeTypeBuilder.SetConstantValue(m_typeBuilder.GetModuleBuilder(), m_fieldTok, m_fieldType, defaultValue); } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { RuntimeModuleBuilder moduleBuilder = (RuntimeModuleBuilder)m_typeBuilder.Module; @@ -160,13 +160,6 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binar m_fieldTok, moduleBuilder.GetMethodMetadataToken(con), binaryAttribute); } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) - { - m_typeBuilder.ThrowIfCreated(); - - customBuilder.CreateCustomAttribute((RuntimeModuleBuilder)m_typeBuilder.Module, m_fieldTok); - } - #endregion } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeGenericTypeParameterBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeGenericTypeParameterBuilder.cs index 6301e2ab4c5098..4245e409b28863 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeGenericTypeParameterBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeGenericTypeParameterBuilder.cs @@ -215,16 +215,11 @@ public override Type MakeArrayType(int rank) #endregion #region Protected Members Overrides - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { m_type.SetGenParamCustomAttribute(con, binaryAttribute); } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) - { - m_type.SetGenParamCustomAttribute(customBuilder); - } - protected override void SetBaseTypeConstraintCore([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? baseTypeConstraint) { m_type.SetParent(baseTypeConstraint); 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 6b2cdad3cc2582..b824378c665e6a 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 @@ -695,7 +695,7 @@ internal Module GetModule() return GetModuleBuilder(); } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { ThrowIfGeneric(); RuntimeTypeBuilder.DefineCustomAttribute(m_module, MetadataToken, @@ -706,15 +706,6 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binar ParseCA(con); } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) - { - ThrowIfGeneric(); - customBuilder.CreateCustomAttribute(m_module, MetadataToken); - - if (IsKnownCA(customBuilder.m_con)) - ParseCA(customBuilder.m_con); - } - // this method should return true for any and every ca that requires more work // than just setting the ca private static bool IsKnownCA(ConstructorInfo con) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeModuleBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeModuleBuilder.cs index 637f7cd6c7e95f..496c24bb105ae9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeModuleBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeModuleBuilder.cs @@ -1289,7 +1289,7 @@ internal int GetSignatureToken(byte[] sigBytes, int sigLength) #region Other - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { RuntimeTypeBuilder.DefineCustomAttribute( this, @@ -1298,11 +1298,6 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binar binaryAttribute); } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) - { - customBuilder.CreateCustomAttribute(this, 1); // This is hard coding the module token to 1 - } - #endregion #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimePropertyBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimePropertyBuilder.cs index ee71d32ceb710f..eccafa7da3f2f6 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimePropertyBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimePropertyBuilder.cs @@ -97,8 +97,7 @@ protected override void AddOtherMethodCore(MethodBuilder mdBuilder) } // Use this function if client decides to form the custom attribute blob themselves - - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { m_containingType.ThrowIfCreated(); RuntimeTypeBuilder.DefineCustomAttribute( @@ -108,13 +107,6 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binar binaryAttribute); } - // Use this function if client wishes to build CustomAttribute using CustomAttributeBuilder - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) - { - m_containingType.ThrowIfCreated(); - customBuilder.CreateCustomAttribute(m_moduleBuilder, m_tkProperty); - } - // Not supported functions in dynamic module. public override object GetValue(object? obj, object?[]? index) { diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeTypeBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeTypeBuilder.cs index 02108de51c1c52..d550f656c32455 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeTypeBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeTypeBuilder.cs @@ -111,13 +111,12 @@ private sealed class CustAttr private readonly byte[]? m_binaryAttribute; private readonly CustomAttributeBuilder? m_customBuilder; - public CustAttr(ConstructorInfo con, byte[] binaryAttribute) + public CustAttr(ConstructorInfo con, ReadOnlySpan binaryAttribute) { ArgumentNullException.ThrowIfNull(con); - ArgumentNullException.ThrowIfNull(binaryAttribute); m_con = con; - m_binaryAttribute = binaryAttribute; + m_binaryAttribute = binaryAttribute.ToArray(); } public CustAttr(CustomAttributeBuilder customBuilder) @@ -173,21 +172,13 @@ private static partial void SetMethodIL(QCallModule module, int tk, [MarshalAs(U [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineCustomAttribute")] private static partial void DefineCustomAttribute(QCallModule module, int tkAssociate, int tkConstructor, - byte[]? attr, int attrLength); + ReadOnlySpan attr, int attrLength); internal static void DefineCustomAttribute(RuntimeModuleBuilder module, int tkAssociate, int tkConstructor, - byte[]? attr) + ReadOnlySpan attr) { - byte[]? localAttr = null; - - if (attr != null) - { - localAttr = new byte[attr.Length]; - Buffer.BlockCopy(attr, 0, localAttr, 0, attr.Length); - } - DefineCustomAttribute(new QCallModule(ref module), tkAssociate, tkConstructor, - localAttr, (localAttr != null) ? localAttr.Length : 0); + attr, attr.Length); } [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineProperty", StringMarshalling = StringMarshalling.Utf16)] @@ -670,7 +661,7 @@ internal void SetGenParamAttributes(GenericParameterAttributes genericParameterA m_genParamAttributes = genericParameterAttributes; } - internal void SetGenParamCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) + internal void SetGenParamCustomAttribute(ConstructorInfo con, ReadOnlySpan binaryAttribute) { CustAttr ca = new CustAttr(con, binaryAttribute); @@ -1858,14 +1849,14 @@ internal int TypeToken } } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) + internal void SetCustomAttribute(ConstructorInfo con, ReadOnlySpan binaryAttribute) { - DefineCustomAttribute(m_module, m_tdType, m_module.GetMethodMetadataToken(con), binaryAttribute); + SetCustomAttributeCore(con, binaryAttribute); } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { - customBuilder.CreateCustomAttribute(m_module, m_tdType); + DefineCustomAttribute(m_module, m_tdType, m_module.GetMethodMetadataToken(con), binaryAttribute); } #endregion diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs index 5a80b4318eddb1..818dccc95dceb3 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs @@ -24,5 +24,10 @@ public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, Pro { ReflectionEmitThrower.ThrowPlatformNotSupportedException(); } + +#pragma warning disable CA1822 // Member 'Ctor' does not access instance data and can be marked as static + internal ConstructorInfo Ctor => default; + internal byte[] Data => default; +#pragma warning restore CA1822 } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs index 3abc6925b7a4af..2ce19ba7a7546b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs @@ -39,17 +39,15 @@ public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) SetCustomAttributeCore(con, binaryAttribute); } - protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute); + protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); public void SetCustomAttribute(CustomAttributeBuilder customBuilder) { ArgumentNullException.ThrowIfNull(customBuilder); - SetCustomAttributeCore(customBuilder); + SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data); } - protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder); - [System.ObsoleteAttribute("Assembly.CodeBase and Assembly.EscapedCodeBase are only included for .NET Framework compatibility. Use Assembly.Location instead.", DiagnosticId = "SYSLIB0012", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] [RequiresAssemblyFiles(ThrowingMessageInRAF)] public override string? CodeBase => throw new NotSupportedException(SR.NotSupported_DynamicAssembly); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs index 3daac6f42875b0..82d95cb8c4f42c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs @@ -31,14 +31,21 @@ public ILGenerator GetILGenerator(int streamSize) protected abstract ILGenerator GetILGeneratorCore(int streamSize); public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) - => SetCustomAttributeCore(con, binaryAttribute); + { + ArgumentNullException.ThrowIfNull(con); + ArgumentNullException.ThrowIfNull(binaryAttribute); + + SetCustomAttributeCore(con, binaryAttribute); + } - protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute); + protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); public void SetCustomAttribute(CustomAttributeBuilder customBuilder) - => SetCustomAttributeCore(customBuilder); + { + ArgumentNullException.ThrowIfNull(customBuilder); - protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder); + SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data); + } public void SetImplementationFlags(MethodImplAttributes attributes) => SetImplementationFlagsCore(attributes); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.cs index f3cdb7f848fb32..8017aabdcdb52c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.cs @@ -35,11 +35,9 @@ public FieldBuilder DefineLiteral(string literalName, object? literalValue) public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) => SetCustomAttributeCore(con, binaryAttribute); - protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute); + protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); public void SetCustomAttribute(CustomAttributeBuilder customBuilder) - => SetCustomAttributeCore(customBuilder); - - protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder); + => SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/EventBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/EventBuilder.cs index 4c4a8f09f6ed49..75b1a9e3606687 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/EventBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/EventBuilder.cs @@ -27,17 +27,15 @@ public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) SetCustomAttributeCore(con, binaryAttribute); } - protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute); + protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); public void SetCustomAttribute(CustomAttributeBuilder customBuilder) { ArgumentNullException.ThrowIfNull(customBuilder); - SetCustomAttributeCore(customBuilder); + SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data); } - protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder); - public void SetRaiseMethod(MethodBuilder mdBuilder) => SetRaiseMethodCore(mdBuilder); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/FieldBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/FieldBuilder.cs index 26092610945625..1e879c09da292e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/FieldBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/FieldBuilder.cs @@ -22,17 +22,15 @@ public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) SetCustomAttributeCore(con, binaryAttribute); } - protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute); + protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); public void SetCustomAttribute(CustomAttributeBuilder customBuilder) { ArgumentNullException.ThrowIfNull(customBuilder); - SetCustomAttributeCore(customBuilder); + SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data); } - protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder); - public void SetOffset(int iOffset) => SetOffsetCore(iOffset); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs index 3594991999021b..dfc38ba67ab088 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs @@ -13,17 +13,15 @@ protected GenericTypeParameterBuilder() public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) => SetCustomAttributeCore(con, binaryAttribute); - protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute); + protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); public void SetCustomAttribute(CustomAttributeBuilder customBuilder) { ArgumentNullException.ThrowIfNull(customBuilder); - SetCustomAttributeCore(customBuilder); + SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data); } - protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder); - public void SetBaseTypeConstraint([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? baseTypeConstraint) => SetBaseTypeConstraintCore(baseTypeConstraint); protected abstract void SetBaseTypeConstraintCore([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? baseTypeConstraint); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs index dab5cd525e029a..ef2c0cea25ab07 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs @@ -56,17 +56,20 @@ public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) SetCustomAttributeCore(con, binaryAttribute); } - protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute); + internal void SetCustomAttribute(ConstructorInfo con, ReadOnlySpan binaryAttribute) + { + SetCustomAttributeCore(con, binaryAttribute); + } + + protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); public void SetCustomAttribute(CustomAttributeBuilder customBuilder) { ArgumentNullException.ThrowIfNull(customBuilder); - SetCustomAttributeCore(customBuilder); + SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data); } - protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder); - public void SetImplementationFlags(MethodImplAttributes attributes) => SetImplementationFlagsCore(attributes); protected abstract void SetImplementationFlagsCore(MethodImplAttributes attributes); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs index 021ddd08ecd86e..21f68439ee3927 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs @@ -134,17 +134,15 @@ public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) SetCustomAttributeCore(con, binaryAttribute); } - protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute); + protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); public void SetCustomAttribute(CustomAttributeBuilder customBuilder) { ArgumentNullException.ThrowIfNull(customBuilder); - SetCustomAttributeCore(customBuilder); + SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data); } - protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder); - public abstract int GetTypeMetadataToken(Type type); public abstract int GetFieldMetadataToken(FieldInfo field); public abstract int GetMethodMetadataToken(MethodInfo method); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/PropertyBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/PropertyBuilder.cs index 924c40f948a128..43b948ac9b9449 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/PropertyBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/PropertyBuilder.cs @@ -27,15 +27,14 @@ public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) SetCustomAttributeCore(con, binaryAttribute); } - protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute); + protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); public void SetCustomAttribute(CustomAttributeBuilder customBuilder) { ArgumentNullException.ThrowIfNull(customBuilder); - SetCustomAttributeCore(customBuilder); - } - protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder); + SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data); + } public void SetGetMethod(MethodBuilder mdBuilder) => SetGetMethodCore(mdBuilder); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs index e715ac81fbb9d5..e3f3b9aa55b5d7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs @@ -277,17 +277,15 @@ public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) SetCustomAttributeCore(con, binaryAttribute); } - protected abstract void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute); + protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); public void SetCustomAttribute(CustomAttributeBuilder customBuilder) { ArgumentNullException.ThrowIfNull(customBuilder); - SetCustomAttributeCore(customBuilder); + SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data); } - protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder); - public void SetParent([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent) => SetParentCore(parent); diff --git a/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs b/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs index 14b8c7b36d9c17..f3cd61d33e8964 100644 --- a/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs +++ b/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs @@ -55,9 +55,8 @@ protected AssemblyBuilder() { } public override System.Type? GetType(string name, bool throwOnError, bool ignoreCase) { throw null; } public override bool IsDefined(System.Type attributeType, bool inherit) { throw null; } public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } - protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute); public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } - protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder); + protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); } [System.FlagsAttribute] public enum AssemblyBuilderAccess @@ -91,9 +90,8 @@ protected ConstructorBuilder() { } public override object Invoke(System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder? binder, object?[]? parameters, System.Globalization.CultureInfo? culture) { throw null; } public override bool IsDefined(System.Type attributeType, bool inherit) { throw null; } public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } - protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute); public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } - protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder); + protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); public void SetImplementationFlags(System.Reflection.MethodImplAttributes attributes) { } protected abstract void SetImplementationFlagsCore(System.Reflection.MethodImplAttributes attributes); public override string ToString() { throw null; } @@ -186,9 +184,8 @@ protected EnumBuilder() { } public override System.Type MakeByRefType() { throw null; } public override System.Type MakePointerType() { throw null; } public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } - protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute); public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } - protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder); + protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); } public abstract partial class EventBuilder { @@ -198,9 +195,8 @@ public void AddOtherMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { } public void SetAddOnMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { } protected abstract void SetAddOnMethodCore(System.Reflection.Emit.MethodBuilder mdBuilder); public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } - protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute); public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } - protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder); + protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); public void SetRaiseMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { } protected abstract void SetRaiseMethodCore(System.Reflection.Emit.MethodBuilder mdBuilder); public void SetRemoveOnMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { } @@ -224,9 +220,8 @@ protected FieldBuilder() { } public void SetConstant(object? defaultValue) { } protected abstract void SetConstantCore(object? defaultValue); public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } - protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute); public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } - protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder); + protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); public void SetOffset(int iOffset) { } protected abstract void SetOffsetCore(int iOffset); public override void SetValue(object? obj, object? val, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder? binder, System.Globalization.CultureInfo? culture) { } @@ -327,9 +322,8 @@ protected GenericTypeParameterBuilder() { } public void SetBaseTypeConstraint([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] System.Type? baseTypeConstraint) { } protected abstract void SetBaseTypeConstraintCore([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] Type? baseTypeConstraint); public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } - protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute); public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } - protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder); + protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); public void SetGenericParameterAttributes(System.Reflection.GenericParameterAttributes genericParameterAttributes) { } protected abstract void SetGenericParameterAttributesCore(System.Reflection.GenericParameterAttributes genericParameterAttributes); public void SetInterfaceConstraints(params System.Type[]? interfaceConstraints) { } @@ -380,9 +374,8 @@ protected MethodBuilder() { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("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 System.Reflection.MethodInfo MakeGenericMethod(params System.Type[] typeArguments) { throw null; } public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } - protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute); public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } - protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder); + protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); public void SetImplementationFlags(System.Reflection.MethodImplAttributes attributes) { } protected abstract void SetImplementationFlagsCore(System.Reflection.MethodImplAttributes attributes); public void SetParameters(params System.Type[] parameterTypes) { } @@ -474,9 +467,8 @@ public void CreateGlobalFunctions() { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Trimming changes metadata tokens")] public override System.Type ResolveType(int metadataToken, System.Type[]? genericTypeArguments, System.Type[]? genericMethodArguments) { throw null; } public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } - protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute); public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } - protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder); + protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); } public abstract partial class PropertyBuilder : System.Reflection.PropertyInfo { @@ -503,9 +495,8 @@ public void AddOtherMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { } public void SetConstant(object? defaultValue) { } protected abstract void SetConstantCore(object? defaultValue); public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } - protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute); public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } - protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder); + protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); public void SetGetMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { } protected abstract void SetGetMethodCore(System.Reflection.Emit.MethodBuilder mdBuilder); public void SetSetMethod(System.Reflection.Emit.MethodBuilder mdBuilder) { } @@ -671,9 +662,8 @@ public void DefineMethodOverride(System.Reflection.MethodInfo methodInfoBody, Sy public override System.Type MakeGenericType(params System.Type[] typeArguments) { throw null; } public override System.Type MakePointerType() { throw null; } public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } - protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, byte[] binaryAttribute); public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } - protected abstract void SetCustomAttributeCore(System.Reflection.Emit.CustomAttributeBuilder customBuilder); + protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); public void SetParent([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] System.Type? parent) { } protected abstract void SetParentCore([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] System.Type? parent); public override string ToString() { throw null; } diff --git a/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx b/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx index b3ad859f052538..dcbd221db545cb 100644 --- a/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx +++ b/src/libraries/System.Reflection.Emit/src/Resources/Strings.resx @@ -141,7 +141,25 @@ The invoked member is not supported in a dynamic module. - - Invalid name. + + 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}'. + + + Custom attribute '{0}' data length is only '{1}'. + + + Custom attribute '{0}' prolog invalid. + + + Custom attribute '{0}' has unknown named type '{1}'. + + + Type '{0}' not handled in the custom attribute value decoder. + + + DllName cannot be empty. \ 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 bc290ba0b8cf39..a647e5707b5cea 100644 --- a/src/libraries/System.Reflection.Emit/src/System.Reflection.Emit.csproj +++ b/src/libraries/System.Reflection.Emit/src/System.Reflection.Emit.csproj @@ -5,6 +5,7 @@ true + diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs index d8543a23602b99..238be3976a40d0 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs @@ -17,6 +17,8 @@ internal sealed class AssemblyBuilderImpl : AssemblyBuilder private ModuleBuilderImpl? _module; private bool _previouslySaved; + internal List? _customAttributes; + internal AssemblyBuilderImpl(AssemblyName name, Assembly coreAssembly, IEnumerable? assemblyAttributes) { ArgumentNullException.ThrowIfNull(name); @@ -77,7 +79,7 @@ internal void Save(Stream stream) } // Add assembly metadata - _metadataBuilder.AddAssembly( + AssemblyDefinitionHandle assemblyHandle = _metadataBuilder.AddAssembly( _metadataBuilder.GetOrAddString(value: _assemblyName.Name!), version: _assemblyName.Version ?? new Version(0, 0, 0, 0), culture: _assemblyName.CultureName == null ? default : _metadataBuilder.GetOrAddString(value: _assemblyName.CultureName), @@ -88,6 +90,7 @@ internal void Save(Stream stream) #pragma warning restore SYSLIB0037 ); + _module.WriteCustomAttributes(_customAttributes, assemblyHandle); // Add module's metadata _module.AppendMetadata(); @@ -128,8 +131,10 @@ protected override ModuleBuilder DefineDynamicModuleCore(string name) return null; } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) => throw new NotImplementedException(); - - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) => throw new NotImplementedException(); + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) + { + _customAttributes ??= new List(); + _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute)); + } } } 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 new file mode 100644 index 00000000000000..2026b79c74e263 --- /dev/null +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/CustomAttributeWrapper.cs @@ -0,0 +1,177 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Buffers.Binary; +using System.Diagnostics.CodeAnalysis; +using System.Reflection.Metadata; + +namespace System.Reflection.Emit +{ + internal readonly struct CustomAttributeWrapper + { + private readonly ConstructorInfo _constructorInfo; + private readonly byte[] _binaryAttribute; + + public CustomAttributeWrapper(ConstructorInfo constructorInfo, ReadOnlySpan binaryAttribute) + { + _constructorInfo = constructorInfo; + _binaryAttribute = binaryAttribute.ToArray(); // TODO: Update to BlobHandle when public API public APi for MetadataBuilder.GetOrAddBlob(ReadOnlySpan) added + } + + public ConstructorInfo Ctor => _constructorInfo; + public byte[] Data => _binaryAttribute; + } + + internal struct CustomAttributeInfo + { + public ConstructorInfo _ctor; + public object?[] _ctorArgs; + public string[] _namedParamNames; + public object?[] _namedParamValues; + private const int Field = 0x53; + private const int EnumType = 0x55; + private const int NullValue = 0xff; + private const int OneByteMask = 0x7f; + private const int TwoByteMask = 0x3f; + private const int FourByteMask = 0x1f; + + internal static CustomAttributeInfo DecodeCustomAttribute(ConstructorInfo ctor, ReadOnlySpan binaryAttribute) + { + int pos = 2; + CustomAttributeInfo info = default; + + if (binaryAttribute.Length < 2) + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidCustomAttributeLength, ctor.DeclaringType, binaryAttribute.Length), nameof(binaryAttribute)); + } + if ((binaryAttribute[0] != 0x01) || (binaryAttribute[1] != 0x00)) + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidProlog, ctor.DeclaringType), nameof(binaryAttribute)); + } + + ParameterInfo[] pi = ctor.GetParameters(); + info._ctor = ctor; + info._ctorArgs = new object?[pi.Length]; + for (int i = 0; i < pi.Length; ++i) + { + info._ctorArgs[i] = DecodeCustomAttributeValue(pi[i].ParameterType, binaryAttribute, pos, out pos); + } + int numNamed = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(pos)); + pos += 2; + + info._namedParamNames = new string[numNamed]; + info._namedParamValues = new object[numNamed]; + for (int i = 0; i < numNamed; ++i) + { + int namedType = binaryAttribute[pos++]; + int dataType = binaryAttribute[pos++]; + + if (dataType == EnumType) + { + // skip bytes for Enum type name; + int len2 = DecodeLen(binaryAttribute, pos, out pos); + pos += len2; + } + + int len = DecodeLen(binaryAttribute, pos, out pos); + string name = StringFromBytes(binaryAttribute, pos, len); + info._namedParamNames[i] = name; + pos += len; + + if (namedType == Field) + { + // For known pseudo custom attributes underlying Enum type is int + Type fieldType = dataType == EnumType ? typeof(int) : ElementTypeToType((PrimitiveSerializationTypeCode)dataType); + info._namedParamValues[i] = DecodeCustomAttributeValue(fieldType, binaryAttribute, pos, out pos); ; + } + else + { + throw new ArgumentException(SR.Format(SR.Argument_UnknownNamedType, ctor.DeclaringType, namedType), nameof(binaryAttribute)); + } + } + + return info; + } + + private static string StringFromBytes(ReadOnlySpan data, int pos, int len) + { + return Text.Encoding.UTF8.GetString(data.Slice(pos, len)); + } + + private static int DecodeLen(ReadOnlySpan data, int pos, out int rpos) + { + int len; + if ((data[pos] & 0x80) == 0) + { + len = (data[pos++] & OneByteMask); + } + else if ((data[pos] & 0x40) == 0) + { + len = ((data[pos] & TwoByteMask) << 8) + data[pos + 1]; + pos += 2; + } + else + { + len = ((data[pos] & FourByteMask) << 24) + (data[pos + 1] << 16) + (data[pos + 2] << 8) + data[pos + 3]; + pos += 4; + } + rpos = pos; + return len; + } + + private static object? DecodeCustomAttributeValue(Type t, ReadOnlySpan data, int pos, out int rpos) + { + switch (Type.GetTypeCode(t)) + { + case TypeCode.String: + if (data[pos] == NullValue) + { + rpos = pos + 1; + return null; + } + int len = DecodeLen(data, pos, out pos); + rpos = pos + len; + return StringFromBytes(data, pos, len); + case TypeCode.Int32: + rpos = pos + 4; + return BinaryPrimitives.ReadInt32LittleEndian(data.Slice(pos)); + case TypeCode.Int16: + rpos = pos + 2; + return BinaryPrimitives.ReadInt16LittleEndian(data.Slice(pos)); + case TypeCode.Boolean: + rpos = pos + 1; + return (data[pos] == 0) ? false : true; + case TypeCode.Object: + int subtype = data[pos]; + pos += 1; + + if (subtype >= 0x02 && subtype <= 0x0e) + { + return DecodeCustomAttributeValue(ElementTypeToType((PrimitiveSerializationTypeCode)subtype), data, pos, out rpos); + } + break; + } + + throw new NotImplementedException(SR.Format(SR.NotImplemented_TypeForValue, t)); + } + + private static Type ElementTypeToType(PrimitiveSerializationTypeCode elementType) => + elementType switch + { + PrimitiveSerializationTypeCode.Boolean => typeof(bool), + PrimitiveSerializationTypeCode.Char => typeof(char), + PrimitiveSerializationTypeCode.SByte => typeof(sbyte), + PrimitiveSerializationTypeCode.Byte => typeof(byte), + PrimitiveSerializationTypeCode.Int16 => typeof(short), + PrimitiveSerializationTypeCode.UInt16 => typeof(ushort), + PrimitiveSerializationTypeCode.Int32 => typeof(int), + PrimitiveSerializationTypeCode.UInt32 => typeof(uint), + PrimitiveSerializationTypeCode.Int64 => typeof(long), + PrimitiveSerializationTypeCode.UInt64 => typeof(ulong), + PrimitiveSerializationTypeCode.Single => typeof(float), + PrimitiveSerializationTypeCode.Double => typeof(double), + PrimitiveSerializationTypeCode.String => typeof(string), + _ => throw new ArgumentException(SR.Argument_InvalidTypeArgument, "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 c017afa9f3580d..3025818ef1a001 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 @@ -1,7 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; namespace System.Reflection.Emit { @@ -9,8 +16,12 @@ internal sealed class FieldBuilderImpl : FieldBuilder { private readonly TypeBuilderImpl _typeBuilder; private readonly string _fieldName; - private readonly FieldAttributes _attributes; private readonly Type _fieldType; + private FieldAttributes _attributes; + + internal MarshallingInfo? _marshallingInfo; + internal int _offset; + internal List? _customAttributes; internal FieldBuilderImpl(TypeBuilderImpl typeBuilder, string fieldName, Type type, FieldAttributes attributes) { @@ -18,14 +29,45 @@ internal FieldBuilderImpl(TypeBuilderImpl typeBuilder, string fieldName, Type ty _typeBuilder = typeBuilder; _fieldType = type; _attributes = attributes & ~FieldAttributes.ReservedMask; + _offset = -1; } - #region MemberInfo Overrides protected override void SetConstantCore(object? defaultValue) => throw new NotImplementedException(); - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) => throw new NotImplementedException(); + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) + { + // Handle pseudo custom attributes + switch (con.ReflectedType!.FullName) + { + case "System.Runtime.InteropServices.FieldOffsetAttribute": + Debug.Assert(binaryAttribute.Length >= 6); + _offset = BinaryPrimitives.ReadInt32LittleEndian(binaryAttribute.Slice(2)); + 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; + case "System.Runtime.CompilerServices.SpecialNameAttribute": + _attributes |= FieldAttributes.SpecialName; + return; + case "System.Runtime.InteropServices.MarshalAsAttribute": + _attributes |= FieldAttributes.HasFieldMarshal; + _marshallingInfo = MarshallingInfo.ParseMarshallingInfo(con, binaryAttribute); + return; + } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) => throw new NotImplementedException(); - protected override void SetOffsetCore(int iOffset) => throw new NotImplementedException(); + _customAttributes ??= new List(); + _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute)); + } + + protected override void SetOffsetCore(int iOffset) + { + ArgumentOutOfRangeException.ThrowIfNegative(iOffset); + + _offset = iOffset; + } + + #region MemberInfo Overrides public override int MetadataToken => throw new NotImplementedException(); @@ -59,5 +101,386 @@ 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 1262ae599fc39c..4f45898d62890d 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 @@ -1,9 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection.Metadata; +using System.Runtime.InteropServices; namespace System.Reflection.Emit { @@ -12,10 +15,14 @@ internal sealed class MethodBuilderImpl : MethodBuilder private readonly Type _returnType; private readonly Type[]? _parameterTypes; private readonly ModuleBuilderImpl _module; - private readonly MethodAttributes _attributes; private readonly string _name; private readonly CallingConventions _callingConventions; private readonly TypeBuilderImpl _declaringType; + private MethodAttributes _attributes; + private MethodImplAttributes _methodImplFlags; + + internal DllImportData? _dllImportData; + internal List? _customAttributes; internal MethodBuilderImpl(string name, MethodAttributes attributes, CallingConventions callingConventions, Type? returnType, Type[]? parameterTypes, ModuleBuilderImpl module, TypeBuilderImpl declaringType) @@ -35,6 +42,8 @@ internal MethodBuilderImpl(string name, MethodAttributes attributes, CallingConv ArgumentNullException.ThrowIfNull(_parameterTypes[i] = parameterTypes[i], nameof(parameterTypes)); } } + + _methodImplFlags = MethodImplAttributes.IL; } internal BlobBuilder GetMethodSignatureBlob() => @@ -44,9 +53,44 @@ internal BlobBuilder GetMethodSignatureBlob() => 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 ILGenerator GetILGeneratorCore(int size) => throw new NotImplementedException(); - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) => throw new NotImplementedException(); - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) => throw new NotImplementedException(); - protected override void SetImplementationFlagsCore(MethodImplAttributes attributes) => throw new NotImplementedException(); + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) + { + // Handle pseudo custom attributes + switch (con.ReflectedType!.FullName) + { + case "System.Runtime.CompilerServices.MethodImplAttribute": + int implValue = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(2)); + _methodImplFlags |= (MethodImplAttributes)implValue; + return; + case "System.Runtime.InteropServices.DllImportAttribute": + { + _dllImportData = DllImportData.CreateDllImportData(CustomAttributeInfo.DecodeCustomAttribute(con, binaryAttribute), out var preserveSig); + _attributes |= MethodAttributes.PinvokeImpl; + if (preserveSig) + { + _methodImplFlags |= MethodImplAttributes.PreserveSig; + } + } + return; + case "System.Runtime.InteropServices.PreserveSigAttribute": + _methodImplFlags |= MethodImplAttributes.PreserveSig; + return; + case "System.Runtime.CompilerServices.SpecialNameAttribute": + _attributes |= MethodAttributes.SpecialName; + return; + case "System.Security.SuppressUnmanagedCodeSecurityAttribute": + _attributes |= MethodAttributes.HasSecurity; + break; + } + + _customAttributes ??= new List(); + _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute)); + } + + protected override void SetImplementationFlagsCore(MethodImplAttributes attributes) + { + _methodImplFlags = attributes; + } protected override void SetSignatureCore(Type? returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers, Type[]? parameterTypes, Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers) => throw new NotImplementedException(); public override string Name => _name; @@ -83,7 +127,7 @@ public override int GetHashCode() => throw new NotImplementedException(); public override MethodImplAttributes GetMethodImplementationFlags() - => throw new NotImplementedException(); + => _methodImplFlags; public override ParameterInfo[] GetParameters() => throw new NotImplementedException(); @@ -98,4 +142,103 @@ 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 8c17b6794c4126..775a5f647a5328 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 @@ -18,6 +18,9 @@ internal sealed class ModuleBuilderImpl : ModuleBuilder private readonly Dictionary _assemblyReferences = new(); private readonly Dictionary _typeReferences = new(); private readonly List _typeDefinitions = new(); + private readonly Dictionary _ctorReferences = new(); + private Dictionary? _moduleReferences; + private List? _customAttributes; private int _nextTypeDefRowId = 1; private int _nextMethodDefRowId = 1; private int _nextFieldDefRowId = 1; @@ -34,7 +37,7 @@ internal ModuleBuilderImpl(string name, Assembly coreAssembly, MetadataBuilder b } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "Types are preserved via s_coreTypes")] - internal Type GetTypeFromCoreAssembly(CoreTypeId typeId) + internal Type GetTypeFromCoreAssembly(CoreTypeId typeId) { if (_coreTypes == null) { @@ -97,7 +100,7 @@ internal Type GetTypeFromCoreAssembly(CoreTypeId typeId) internal void AppendMetadata() { // Add module metadata - _metadataBuilder.AddModule( + ModuleDefinitionHandle moduleHandle = _metadataBuilder.AddModule( generation: 0, moduleName: _metadataBuilder.GetOrAddString(_name), mvid: _metadataBuilder.GetOrAddGuid(Guid.NewGuid()), @@ -111,7 +114,9 @@ internal void AppendMetadata() name: _metadataBuilder.GetOrAddString(""), baseType: default, fieldList: MetadataTokens.FieldDefinitionHandle(1), - methodList: MetadataTokens.MethodDefinitionHandle(1)); ; + methodList: MetadataTokens.MethodDefinitionHandle(1)); + + WriteCustomAttributes(_customAttributes, moduleHandle); // Add each type definition to metadata table. foreach (TypeBuilderImpl typeBuilder in _typeDefinitions) @@ -124,22 +129,100 @@ internal void AppendMetadata() TypeDefinitionHandle typeDefinitionHandle = AddTypeDefinition(typeBuilder, parent, _nextMethodDefRowId, _nextFieldDefRowId); Debug.Assert(typeBuilder._handle.Equals(typeDefinitionHandle)); + WriteCustomAttributes(typeBuilder._customAttributes, typeDefinitionHandle); - // Add each method definition to metadata table. - foreach (MethodBuilderImpl method in typeBuilder._methodDefStore) + foreach (MethodBuilderImpl method in typeBuilder._methodDefinitions) { - AddMethodDefinition(method, method.GetMethodSignatureBlob()); + MethodDefinitionHandle methodHandle = AddMethodDefinition(method, method.GetMethodSignatureBlob()); + WriteCustomAttributes(method._customAttributes, methodHandle); _nextMethodDefRowId++; + + if (method._dllImportData != null) + { + AddMethodImport(methodHandle, method._dllImportData.EntryPoint ?? method.Name, + method._dllImportData.Flags, GetModuleReference(method._dllImportData.ModuleName)); + } } - foreach (FieldBuilderImpl field in typeBuilder._fieldDefStore) + foreach (FieldBuilderImpl field in typeBuilder._fieldDefinitions) { - AddFieldDefinition(field, MetadataSignatureHelper.FieldSignatureEncoder(field.FieldType, this)); + FieldDefinitionHandle fieldHandle = AddFieldDefinition(field, MetadataSignatureHelper.FieldSignatureEncoder(field.FieldType, this)); + WriteCustomAttributes(field._customAttributes, fieldHandle); _nextFieldDefRowId++; + + if (field._offset > 0 && (typeBuilder.Attributes & TypeAttributes.ExplicitLayout) != 0) + { + AddFieldLayout(fieldHandle, field._offset); + } + + if (field._marshallingInfo != null) + { + AddFieldMarshalling(fieldHandle, field._marshallingInfo.PopulateMarshallingBlob(_metadataBuilder)); + } } } } + private ModuleReferenceHandle GetModuleReference(string moduleName) + { + _moduleReferences ??= new Dictionary(); + + if (!_moduleReferences.TryGetValue(moduleName, out var handle)) + { + handle = AddModuleReference(moduleName); + _moduleReferences.Add(moduleName, handle); + } + + return handle; + } + + internal void WriteCustomAttributes(List? customAttributes, EntityHandle parent) + { + if (customAttributes != null) + { + foreach (CustomAttributeWrapper customAttribute in customAttributes) + { + _metadataBuilder.AddCustomAttribute(parent, GetConstructorHandle(customAttribute.Ctor), + _metadataBuilder.GetOrAddBlob(customAttribute.Data)); + } + } + } + + private MemberReferenceHandle GetConstructorHandle(ConstructorInfo constructorInfo) + { + if (!_ctorReferences.TryGetValue(constructorInfo, out var constructorHandle)) + { + TypeReferenceHandle parentHandle = GetTypeReference(constructorInfo.DeclaringType!); + constructorHandle = AddConstructorReference(parentHandle, constructorInfo); + _ctorReferences.Add(constructorInfo, constructorHandle); + } + + return constructorHandle; + } + + private TypeReferenceHandle GetTypeReference(Type type) + { + if (!_typeReferences.TryGetValue(type, out var typeHandle)) + { + typeHandle = AddTypeReference(type, GetAssemblyReference(type.Assembly)); + _typeReferences.Add(type, typeHandle); + } + + return typeHandle; + } + + private AssemblyReferenceHandle GetAssemblyReference(Assembly assembly) + { + if (!_assemblyReferences.TryGetValue(assembly, out var handle)) + { + AssemblyName aName = assembly.GetName(); + handle = AddAssemblyReference(aName.Name!, aName.Version, aName.CultureName, aName.GetPublicKeyToken(), aName.Flags, aName.ContentType); + _assemblyReferences.Add(assembly, handle); + } + + return handle; + } + private FieldDefinitionHandle AddFieldDefinition(FieldBuilderImpl field, BlobBuilder fieldSignature) => _metadataBuilder.AddFieldDefinition( attributes: field.Attributes, @@ -158,45 +241,48 @@ private TypeDefinitionHandle AddTypeDefinition(TypeBuilderImpl type, EntityHandl private MethodDefinitionHandle AddMethodDefinition(MethodBuilderImpl method, BlobBuilder methodSignature) => _metadataBuilder.AddMethodDefinition( attributes: method.Attributes, - implAttributes: MethodImplAttributes.IL, + 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(1)); private TypeReferenceHandle AddTypeReference(Type type, AssemblyReferenceHandle parent) => _metadataBuilder.AddTypeReference( resolutionScope: parent, @namespace: (type.Namespace == null) ? default : _metadataBuilder.GetOrAddString(type.Namespace), - name: _metadataBuilder.GetOrAddString(type.Name) - ); + name: _metadataBuilder.GetOrAddString(type.Name)); - private TypeReferenceHandle GetTypeReference(Type type) + private MemberReferenceHandle AddConstructorReference(TypeReferenceHandle parent, ConstructorInfo method) { - if (!_typeReferences.TryGetValue(type, out var parentHandle)) - { - parentHandle = AddTypeReference(type, GetAssemblyReference(type.Assembly)); - _typeReferences.Add(type, parentHandle); - } - - return parentHandle; + var blob = MetadataSignatureHelper.ConstructorSignatureEncoder(method.GetParameters(), this); + return _metadataBuilder.AddMemberReference( + parent: parent, + name: _metadataBuilder.GetOrAddString(method.Name), + signature: _metadataBuilder.GetOrAddBlob(blob)); } - private AssemblyReferenceHandle GetAssemblyReference(Assembly assembly) - { - if (!_assemblyReferences.TryGetValue(assembly, out var handle)) - { - AssemblyName aName = assembly.GetName(); - handle = AddAssemblyReference(aName.Name!, aName.Version, aName.CultureName, aName.GetPublicKeyToken(), aName.Flags, aName.ContentType); - _assemblyReferences.Add(assembly, handle); - } + private void AddMethodImport(MethodDefinitionHandle methodHandle, string name, + MethodImportAttributes attributes, ModuleReferenceHandle moduleHandle) => + _metadataBuilder.AddMethodImport( + method: methodHandle, + attributes: attributes, + name: _metadataBuilder.GetOrAddString(name), + module: moduleHandle); - return handle; + private ModuleReferenceHandle AddModuleReference(string moduleName) => + _metadataBuilder.AddModuleReference(moduleName: _metadataBuilder.GetOrAddString(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 AssemblyReferenceHandle AddAssemblyReference(string name, Version? version, - string? culture, byte[]? publicKeyToken, AssemblyNameFlags flags, AssemblyContentType contentType) => + private AssemblyReferenceHandle AddAssemblyReference(string name, Version? version, string? culture, + byte[]? publicKeyToken, AssemblyNameFlags flags, AssemblyContentType contentType) => _metadataBuilder.AddAssemblyReference( name: _metadataBuilder.GetOrAddString(name), version: version ?? new Version(0, 0, 0, 0), @@ -233,14 +319,17 @@ internal EntityHandle GetTypeHandle(Type type) protected override TypeBuilder DefineTypeCore(string name, TypeAttributes attr, [DynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)(-1))] Type? parent, Type[]? interfaces, PackingSize packingSize, int typesize) { TypeDefinitionHandle typeHandle = MetadataTokens.TypeDefinitionHandle(++_nextTypeDefRowId); - TypeBuilderImpl _type = new TypeBuilderImpl(name, attr, parent, this, typeHandle); + TypeBuilderImpl _type = new TypeBuilderImpl(name, attr, parent, this, typeHandle, packingSize, typesize); _typeDefinitions.Add(_type); return _type; } protected override FieldBuilder DefineUninitializedDataCore(string name, int size, FieldAttributes attributes) => throw new NotImplementedException(); protected override MethodInfo GetArrayMethodCore(Type arrayClass, string methodName, CallingConventions callingConvention, Type? returnType, Type[]? parameterTypes) => throw new NotImplementedException(); - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) => throw new NotSupportedException(); - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) => throw new NotSupportedException(); + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) + { + _customAttributes ??= new List(); + _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute)); + } public override int GetSignatureMetadataToken(SignatureHelper signature) => throw new NotImplementedException(); } } diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs index ad1701c35ecb97..7bdc5cf8734d71 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -19,17 +18,37 @@ internal static BlobBuilder FieldSignatureEncoder(Type fieldType, ModuleBuilderI return fieldSignature; } + internal static BlobBuilder ConstructorSignatureEncoder(ParameterInfo[]? parameters, ModuleBuilderImpl module) + { + BlobBuilder constructorSignature = new(); + + new BlobEncoder(constructorSignature). + MethodSignature(isInstanceMethod: true). + Parameters((parameters == null) ? 0 : parameters.Length, out ReturnTypeEncoder retType, out ParametersEncoder parameterEncoder); + + retType.Void(); + + if (parameters != null) + { + Type[]? typeParameters = Array.ConvertAll(parameters, parameter => parameter.ParameterType); + + foreach (Type parameter in typeParameters) + { + WriteSignatureForType(parameterEncoder.AddParameter().Type(), parameter, module); + } + } + + return constructorSignature; + } + internal static BlobBuilder MethodSignatureEncoder(ModuleBuilderImpl module, Type[]? parameters, Type? returnType, bool isInstance) { // Encoding return type and parameters. BlobBuilder methodSignature = new(); - ParametersEncoder parEncoder; - ReturnTypeEncoder retEncoder; - new BlobEncoder(methodSignature). MethodSignature(isInstanceMethod: isInstance). - Parameters((parameters == null) ? 0 : parameters.Length, out retEncoder, out parEncoder); + Parameters((parameters == null) ? 0 : parameters.Length, out ReturnTypeEncoder retEncoder, out ParametersEncoder parEncoder); if (returnType != null && returnType != module.GetTypeFromCoreAssembly(CoreTypeId.Void)) { diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs index 16558aa05ceef4..d2f0b5aaf1651d 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; using System.Globalization; +using System.Runtime.InteropServices; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -12,22 +12,29 @@ namespace System.Reflection.Emit { internal sealed class TypeBuilderImpl : TypeBuilder { - internal List _methodDefStore = new(); - internal List _fieldDefStore = new(); private readonly ModuleBuilderImpl _module; private readonly string _name; private readonly string? _namespace; - internal readonly TypeDefinitionHandle _handle; [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] private Type? _typeParent; private TypeAttributes _attributes; + private PackingSize _packingSize; + private int _typeSize; + + internal readonly TypeDefinitionHandle _handle; + internal readonly List _methodDefinitions = new(); + internal readonly List _fieldDefinitions = new(); + internal List? _customAttributes; internal TypeBuilderImpl(string fullName, TypeAttributes typeAttributes, - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent, ModuleBuilderImpl module, TypeDefinitionHandle handle) + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent, ModuleBuilderImpl module, + TypeDefinitionHandle handle, PackingSize packingSize, int typeSize) { _name = fullName; _module = module; _attributes = typeAttributes; + _packingSize = packingSize; + _typeSize = typeSize; SetParent(parent); _handle = handle; @@ -41,8 +48,8 @@ internal TypeBuilderImpl(string fullName, TypeAttributes typeAttributes, } internal ModuleBuilderImpl GetModuleBuilder() => _module; - protected override PackingSize PackingSizeCore => throw new NotImplementedException(); - protected override int SizeCore => throw new NotImplementedException(); + protected override PackingSize PackingSizeCore => _packingSize; + protected override int SizeCore => _typeSize; protected override void AddInterfaceImplementationCore([DynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)(-1))] Type interfaceType) => throw new NotImplementedException(); [return: DynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)(-1))] protected override TypeInfo CreateTypeInfoCore() => throw new NotImplementedException(); @@ -52,7 +59,7 @@ internal TypeBuilderImpl(string fullName, TypeAttributes typeAttributes, protected override FieldBuilder DefineFieldCore(string fieldName, Type type, Type[]? requiredCustomModifiers, Type[]? optionalCustomModifiers, FieldAttributes attributes) { var field = new FieldBuilderImpl(this, fieldName, type, attributes); - _fieldDefStore.Add(field); + _fieldDefinitions.Add(field); return field; } protected override GenericTypeParameterBuilder[] DefineGenericParametersCore(params string[] names) => throw new NotImplementedException(); @@ -60,7 +67,7 @@ protected override FieldBuilder DefineFieldCore(string fieldName, Type type, Typ protected override MethodBuilder DefineMethodCore(string name, MethodAttributes attributes, CallingConventions callingConvention, Type? returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers, Type[]? parameterTypes, Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers) { MethodBuilderImpl methodBuilder = new(name, attributes, callingConvention, returnType, parameterTypes, _module, this); - _methodDefStore.Add(methodBuilder); + _methodDefinitions.Add(methodBuilder); return methodBuilder; } @@ -72,8 +79,85 @@ protected override MethodBuilder DefineMethodCore(string name, MethodAttributes protected override ConstructorBuilder DefineTypeInitializerCore() => throw new NotImplementedException(); protected override FieldBuilder DefineUninitializedDataCore(string name, int size, FieldAttributes attributes) => throw new NotImplementedException(); protected override bool IsCreatedCore() => throw new NotImplementedException(); - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) => throw new NotImplementedException(); - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) => throw new NotImplementedException(); + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) + { + // Handle pseudo custom attributes + switch (con.ReflectedType!.FullName) + { + case "System.Runtime.InteropServices.StructLayoutAttribute": + ParseStructLayoutAttribute(con, binaryAttribute); + return; + case "System.Runtime.CompilerServices.SpecialNameAttribute": + _attributes |= TypeAttributes.SpecialName; + return; + case "System.SerializableAttribute": +#pragma warning disable SYSLIB0050 // 'TypeAttributes.Serializable' is obsolete: 'Formatter-based serialization is obsolete and should not be used'. + _attributes |= TypeAttributes.Serializable; +#pragma warning restore SYSLIB0050 + return; + case "System.Runtime.InteropServices.ComImportAttribute": + _attributes |= TypeAttributes.Import; + return; + case "System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeImportAttribute": + _attributes |= TypeAttributes.WindowsRuntime; + return; + case "System.Security.SuppressUnmanagedCodeSecurityAttribute": // It says has no effect in .NET Core, maybe remove? + _attributes |= TypeAttributes.HasSecurity; + break; + } + + _customAttributes ??= new List(); + _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute)); + } + + private void ParseStructLayoutAttribute(ConstructorInfo con, ReadOnlySpan binaryAttribute) + { + CustomAttributeInfo attributeInfo = CustomAttributeInfo.DecodeCustomAttribute(con, binaryAttribute); + LayoutKind layoutKind = (LayoutKind)attributeInfo._ctorArgs[0]!; + _attributes &= ~TypeAttributes.LayoutMask; + _attributes |= layoutKind switch + { + LayoutKind.Auto => TypeAttributes.AutoLayout, + LayoutKind.Explicit => TypeAttributes.ExplicitLayout, + LayoutKind.Sequential => TypeAttributes.SequentialLayout, + _ => TypeAttributes.AutoLayout, + }; + + for (int i = 0; i < attributeInfo._namedParamNames.Length; ++i) + { + string name = attributeInfo._namedParamNames[i]; + int value = (int)attributeInfo._namedParamValues[i]!; + + switch (name) + { + case "CharSet": + switch ((CharSet)value) + { + case CharSet.None: + case CharSet.Ansi: + _attributes &= ~(TypeAttributes.UnicodeClass | TypeAttributes.AutoClass); + break; + case CharSet.Unicode: + _attributes &= ~TypeAttributes.AutoClass; + _attributes |= TypeAttributes.UnicodeClass; + break; + case CharSet.Auto: + _attributes &= ~TypeAttributes.UnicodeClass; + _attributes |= TypeAttributes.AutoClass; + break; + } + break; + case "Pack": + _packingSize = (PackingSize)value; + break; + case "Size": + _typeSize = value; + break; + default: + throw new ArgumentException(SR.Format(SR.Argument_UnknownNamedType, con.DeclaringType, name), nameof(binaryAttribute)); + } + } + } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2074:DynamicallyAccessedMembers", Justification = "TODO: Need to figure out how to preserve System.Object public constructor")] diff --git a/src/libraries/System.Reflection.Emit/tests/GenericTypeParameterBuilder/GenericTypeParameterBuilderSetCustomAttribute.cs b/src/libraries/System.Reflection.Emit/tests/GenericTypeParameterBuilder/GenericTypeParameterBuilderSetCustomAttribute.cs index e177c08dab26a9..aea595e0761c68 100644 --- a/src/libraries/System.Reflection.Emit/tests/GenericTypeParameterBuilder/GenericTypeParameterBuilderSetCustomAttribute.cs +++ b/src/libraries/System.Reflection.Emit/tests/GenericTypeParameterBuilder/GenericTypeParameterBuilderSetCustomAttribute.cs @@ -29,17 +29,6 @@ public void SetCustomAttribute_ConstructorInfo_ByteArray_NullAttributeConstructo AssertExtensions.Throws("con", () => typeParams[0].SetCustomAttribute(null, new byte[128])); } - [Fact] - public void SetCustomAttribute_ConstructorInfo_ByteArray_NullBinaryAttribute_ThrowsArgumentNullException() - { - TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); - string[] typeParamNames = new string[] { "TFirst" }; - GenericTypeParameterBuilder[] typeParams = type.DefineGenericParameters(typeParamNames); - ConstructorInfo attributeConstructor = typeof(HelperAttribute).GetConstructor(new Type[0]); - - AssertExtensions.Throws("binaryAttribute", () => typeParams[0].SetCustomAttribute(attributeConstructor, null)); - } - [Fact] public void SetCustomAttribute_CustomAttributeBuilder() { diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveCustomAttributeTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveCustomAttributeTests.cs new file mode 100644 index 00000000000000..0f1d3c929b3e36 --- /dev/null +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveCustomAttributeTests.cs @@ -0,0 +1,407 @@ +// 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; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; +using Xunit; + +namespace System.Reflection.Emit.Tests +{ + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public class AssemblySaveCustomAttributeTests + { + private List _attributes = new List + { + new CustomAttributeBuilder(s_comVisiblePair.con, s_comVisiblePair.args), + new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args) + }; + + private static readonly Type s_comVisibleType = typeof(ComVisibleAttribute); + private static readonly Type s_guideType = typeof(GuidAttribute); + private static readonly (ConstructorInfo con, object[] args) s_comVisiblePair = (s_comVisibleType.GetConstructor(new Type[] { typeof(bool) }), new object[] { true }); + private static readonly (ConstructorInfo con, object[] args) s_guidPair = (s_guideType.GetConstructor(new Type[] { typeof(string) }), new object[] { "9ED54F84-A89D-4fcd-A854-44251E925F09" }); + + private static AssemblyName PopulateAssemblyName() + { + AssemblyName assemblyName = new AssemblyName("MyDynamicAssembly"); + assemblyName.Version = new Version("7.0.0.0"); + assemblyName.CultureInfo = Globalization.CultureInfo.InvariantCulture; + return assemblyName; + } + + [Fact] + public void AssemblyModuleWithCustomAttributes() + { + AssemblyName assemblyName = PopulateAssemblyName(); + + using (TempFile file = TempFile.Create()) + { + WriteAssemblyToDisk(assemblyName, Type.EmptyTypes, file.Path, _attributes, _attributes); + + Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path); + Module moduleFromDisk = assemblyFromDisk.Modules.First(); + + AssemblyTools.AssertAssemblyNameAndModule(assemblyName, assemblyFromDisk.GetName(), moduleFromDisk); + ValidateAttributes(assemblyFromDisk.GetCustomAttributesData()); + ValidateAttributes(moduleFromDisk.GetCustomAttributesData()); + } + } + + [Fact] + public void MethodFieldWithCustomAttributes() + { + Type[] types = new Type[] { typeof(IMultipleMethod), typeof(IOneMethod), typeof(StructWithFields) }; + + using (TempFile file = TempFile.Create()) + { + WriteAssemblyToDisk(PopulateAssemblyName(), types, file.Path, typeAttributes: _attributes, + methodAttributes: _attributes, fieldAttributes: _attributes); + + Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path); + + Module moduleFromDisk = assemblyFromDisk.Modules.First(); + Type[] typesFromDisk = moduleFromDisk.GetTypes(); + + Assert.Equal(types.Length, typesFromDisk.Length); + + for (int i = 0; i < types.Length; i++) + { + Type typeFromDisk = typesFromDisk[i]; + Type sourceType = types[i]; + MethodInfo[] methodsFromDisk = typeFromDisk.IsValueType ? typeFromDisk.GetMethods(BindingFlags.DeclaredOnly) : typeFromDisk.GetMethods(); + FieldInfo[] fieldsFromDisk = typeFromDisk.GetFields(); + + AssemblyTools.AssertTypeProperties(sourceType, typeFromDisk); + AssemblyTools.AssertMethods(sourceType.IsValueType ? sourceType.GetMethods(BindingFlags.DeclaredOnly) : sourceType.GetMethods(), methodsFromDisk); + AssemblyTools.AssertFields(sourceType.GetFields(), fieldsFromDisk); + ValidateAttributes(typeFromDisk.GetCustomAttributesData()); + + for (int j = 0; j < methodsFromDisk.Length; j++) + { + ValidateAttributes(methodsFromDisk[j].GetCustomAttributesData()); + } + + for (int j = 0; j < fieldsFromDisk.Length; j++) + { + ValidateAttributes(fieldsFromDisk[j].GetCustomAttributesData()); + } + } + } + } + + private void ValidateAttributes(IList attributesFromDisk) + { + Assert.Equal(_attributes.Count, attributesFromDisk.Count); + + foreach (var attribute in attributesFromDisk) + { + if (attribute.AttributeType.Name == s_comVisibleType.Name) + { + Assert.Equal(s_comVisiblePair.con.MetadataToken, attribute.Constructor.MetadataToken); + Assert.Equal(s_comVisiblePair.args[0].GetType().FullName, attribute.ConstructorArguments[0].ArgumentType.FullName); + Assert.Equal(true, attribute.ConstructorArguments[0].Value); + } + else + { + Assert.Equal(s_guidPair.con.MetadataToken, attribute.Constructor.MetadataToken); + Assert.Equal(s_guidPair.args[0].GetType().FullName, attribute.ConstructorArguments[0].ArgumentType.FullName); + Assert.Equal(attribute.AttributeType.Name, s_guideType.Name); + Assert.Equal(s_guidPair.args[0], attribute.ConstructorArguments[0].Value); + } + } + } + + private static void WriteAssemblyToDisk(AssemblyName assemblyName, Type[] types, string fileLocation, List? assemblyAttributes = null, + List? moduleAttributes = null, List? typeAttributes = null, + List? methodAttributes = null, List? fieldAttributes = null) + { + AssemblyBuilder assemblyBuilder = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(assemblyName, assemblyAttributes, typeof(string), out MethodInfo saveMethod); + ModuleBuilder mb = assemblyBuilder.DefineDynamicModule(assemblyName.Name); + PopulateMembersForModule(mb, types, moduleAttributes, typeAttributes, methodAttributes, fieldAttributes); + saveMethod.Invoke(assemblyBuilder, new object[] { fileLocation }); + } + + private static void PopulateMembersForModule(ModuleBuilder mb, Type[] types, List? moduleAttributes, + List? typeAttributes, List? methodAttributes, List? fieldAttributes) + { + if (moduleAttributes != null) + { + moduleAttributes.ForEach(mb.SetCustomAttribute); + } + + foreach (Type type in types) + { + 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)); + DefineFieldsAndSetAttributes(fieldAttributes, type.GetFields(), tb); + } + } + + private static void DefineFieldsAndSetAttributes(List? fieldAttributes, FieldInfo[] fields, TypeBuilder tb) + { + foreach (FieldInfo field in fields) + { + FieldBuilder fb = tb.DefineField(field.Name, field.FieldType, field.Attributes); + fieldAttributes.ForEach(fb.SetCustomAttribute); + } + } + + private static void DefineMethodsAndSetAttributes(List methodAttributes, TypeBuilder tb, MethodInfo[] methods) + { + foreach (var method in methods) + { + MethodBuilder meb = tb.DefineMethod(method.Name, method.Attributes, method.CallingConvention, method.ReturnType, null); + methodAttributes.ForEach(meb.SetCustomAttribute); + } + } + + [Fact] + public void CreateStructWithPseudoCustomAttributesTest() + { + using (TempFile file = TempFile.Create()) + { + Type type = typeof(StructWithFields); + List typeAttributes = new() { new CustomAttributeBuilder(typeof(SerializableAttribute).GetConstructor(Type.EmptyTypes), new object[] { }), + new CustomAttributeBuilder(typeof(StructLayoutAttribute).GetConstructor(new Type[] { typeof(LayoutKind) }), new object[] { LayoutKind.Explicit }, + typeof(StructLayoutAttribute).GetFields() , new object[]{32, 64, CharSet.Unicode}), + new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args), + new CustomAttributeBuilder(typeof(SpecialNameAttribute).GetConstructor(Type.EmptyTypes), new object[] { }) + }; + CustomAttributeBuilder[] fieldAttributes = new[] { new CustomAttributeBuilder(typeof(NonSerializedAttribute).GetConstructor(Type.EmptyTypes), new object[] { }), + new CustomAttributeBuilder(typeof(FieldOffsetAttribute).GetConstructor(new Type[] { typeof(int) }), new object[] { 2 }), + new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args), + new CustomAttributeBuilder(typeof(MarshalAsAttribute).GetConstructor(new Type[] { typeof(UnmanagedType) }), new object[] { UnmanagedType.I4}), + new CustomAttributeBuilder(typeof(SpecialNameAttribute).GetConstructor(Type.EmptyTypes), new object[] { }) + }; + + AssemblyBuilder ab = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod( + PopulateAssemblyName(), null, typeof(string), out MethodInfo saveMethod); + TypeBuilder tb = ab.DefineDynamicModule("Module").DefineType(type.FullName, type.Attributes, type.BaseType); + DefineFieldsAndSetAttributes(fieldAttributes.ToList(), type.GetFields(), tb); + typeAttributes.ForEach(tb.SetCustomAttribute); + saveMethod.Invoke(ab, new object[] { file.Path }); + + Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path); + Module moduleFromDisk = assemblyFromDisk.Modules.First(); + Type testType = moduleFromDisk.GetTypes()[0]; + IList attributesFromDisk = testType.GetCustomAttributesData(); + + Assert.Equal(typeAttributes.Count - 3, attributesFromDisk.Count); // 3 pseudo attributes + Assert.True((testType.Attributes & TypeAttributes.Serializable) != 0); // SerializableAttribute + Assert.True((testType.Attributes & TypeAttributes.SpecialName) != 0); // SpecialNameAttribute + Assert.True((testType.Attributes & TypeAttributes.ExplicitLayout) != 0); // StructLayoutAttribute + Assert.True((testType.Attributes & TypeAttributes.UnicodeClass) != 0); // StructLayoutAttribute, not sure if we could test the PackingSize and Size + + for (int i = 0; i < attributesFromDisk.Count; i++) + { + switch (attributesFromDisk[i].AttributeType.Name) + { + case "GuidAttribute": + Assert.Equal(s_guidPair.args[0], attributesFromDisk[i].ConstructorArguments[0].Value); + break; + default: + Assert.Fail($"Not expected attribute : {attributesFromDisk[i].AttributeType.Name}"); + break; + } + } + + FieldInfo field = testType.GetFields()[0]; + IList fieldAttributesFromDisk = field.GetCustomAttributesData(); + + Assert.Equal(3, fieldAttributesFromDisk.Count); + Assert.True((field.Attributes & FieldAttributes.NotSerialized) != 0); // NonSerializedAttribute + Assert.True((field.Attributes & FieldAttributes.SpecialName) != 0); // SpecialNameAttribute + Assert.True((field.Attributes & FieldAttributes.HasFieldMarshal) != 0); // MarshalAsAttribute + + for (int i = 0; i < fieldAttributesFromDisk.Count; i++) + { + switch (fieldAttributesFromDisk[i].AttributeType.Name) + { + case "FieldOffsetAttribute": + Assert.Equal(2, fieldAttributesFromDisk[i].ConstructorArguments[0].Value); + break; + case "MarshalAsAttribute": + Assert.Equal(UnmanagedType.I4, (UnmanagedType)fieldAttributesFromDisk[i].ConstructorArguments[0].Value); + break; + case "GuidAttribute": + Assert.Equal(s_guidPair.args[0], fieldAttributesFromDisk[i].ConstructorArguments[0].Value); + break; + default: + Assert.Fail($"Not expected attribute : {fieldAttributesFromDisk[i].AttributeType.Name}"); + break; + } + } + } + } + + [Fact] + public void InterfacesWithPseudoCustomAttributes() + { + using (TempFile file = TempFile.Create()) + { + 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); + TypeBuilder tb = ab.DefineDynamicModule("Module").DefineType(type.FullName, type.Attributes); + typeAttributes.ForEach(tb.SetCustomAttribute); + DefineMethodsAndSetAttributes(methodAttributes.ToList(), tb, type.GetMethods()); + saveMethod.Invoke(ab, new object[] { file.Path }); + + Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path); + Type testType = assemblyFromDisk.Modules.First().GetTypes()[0]; + IList attributesFromDisk = testType.GetCustomAttributesData(); + + Assert.Equal(typeAttributes.Count, attributesFromDisk.Count); + Assert.True((testType.Attributes & TypeAttributes.Import) != 0); // ComImportAttribute + Assert.True((testType.Attributes & TypeAttributes.HasSecurity) != 0); // SuppressUnmanagedCodeSecurityAttribute + for (int i = 0; i < attributesFromDisk.Count; i++) + { + switch (attributesFromDisk[i].AttributeType.Name) + { + case "ComImportAttribute": // just making sure that these attributes are expected + case "SuppressUnmanagedCodeSecurityAttribute": + break; + case "GuidAttribute": + Assert.Equal(s_guidPair.args[0], attributesFromDisk[i].ConstructorArguments[0].Value); + break; + default: + Assert.Fail($"Not expected attribute : {attributesFromDisk[i].AttributeType.Name}"); + break; + } + } + + foreach (var method in testType.GetMethods()) + { + IList methodAttributesFromDisk = method.GetCustomAttributesData(); + + Assert.True((method.Attributes & MethodAttributes.HasSecurity) != 0); // SuppressUnmanagedCodeSecurityAttribute + Assert.True((method.Attributes & MethodAttributes.SpecialName) != 0); // SpecialNameAttribute + MethodImplAttributes methodImpl = method.GetMethodImplementationFlags(); + 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); + + for (int i = 0; i < methodAttributesFromDisk.Count; i++) + { + switch (methodAttributesFromDisk[i].AttributeType.Name) + { + case "SuppressUnmanagedCodeSecurityAttribute": + case "PreserveSigAttribute": + break; + case "GuidAttribute": + Assert.Equal(s_guidPair.args[0], methodAttributesFromDisk[i].ConstructorArguments[0].Value); + break; + case "DllImportAttribute": + { + CustomAttributeData attribute = methodAttributesFromDisk[i]; + Assert.Equal("test.dll", attribute.ConstructorArguments[0].Value); + + for (int j = 0; j < attribute.NamedArguments.Count; j++) + { + switch (attribute.NamedArguments[j].MemberName) + { + case "CharSet": + Assert.Equal(CharSet.Ansi, (CharSet)attribute.NamedArguments[j].TypedValue.Value); + break; + case "SetLastError": + Assert.True((bool)attribute.NamedArguments[j].TypedValue.Value); + break; + case "CallingConvention": + Assert.Equal(CallingConvention.FastCall, (CallingConvention)attribute.NamedArguments[j].TypedValue.Value); + break; + case "BestFitMapping": + Assert.True((bool)attribute.NamedArguments[j].TypedValue.Value); + break; + case "ThrowOnUnmappableChar": + Assert.False((bool)attribute.NamedArguments[j].TypedValue.Value); + break; + } + } + } + break; + default: + Assert.Fail($"Not expected attribute : {methodAttributesFromDisk[i].AttributeType.Name}"); + break; + } + } + } + } + } + + private static readonly ConstructorInfo marshalAsEnumCtor = typeof(MarshalAsAttribute).GetConstructor(new Type[] { typeof(UnmanagedType) }); + private static readonly ConstructorInfo marshalAsShortCtor = typeof(MarshalAsAttribute).GetConstructor(new Type[] { typeof(short) }); + + public static IEnumerable MarshalAsAttributeWithVariousFields() + { + yield return new object[] { new CustomAttributeBuilder(marshalAsEnumCtor, new object[] { UnmanagedType.LPStr }), UnmanagedType.LPStr }; + yield return new object[] { new CustomAttributeBuilder(marshalAsShortCtor, new object[] { (short)21 }), UnmanagedType.LPWStr }; + yield return new object[] { new CustomAttributeBuilder(marshalAsShortCtor, new object[] { (short)19 }), UnmanagedType.BStr }; + yield return new object[] { new CustomAttributeBuilder(marshalAsEnumCtor, new object[] { UnmanagedType.ByValTStr }, + new FieldInfo[] { typeof(MarshalAsAttribute).GetField("SizeConst") }, new object[] { 256 }) , UnmanagedType.ByValTStr }; + yield return new object[] { new CustomAttributeBuilder(marshalAsEnumCtor, new object[] { UnmanagedType.CustomMarshaler }, + new FieldInfo[] { typeof(MarshalAsAttribute).GetField("MarshalType"), typeof(MarshalAsAttribute).GetField("MarshalCookie") }, + new object[] { typeof(EmptyTestClass).AssemblyQualifiedName, "MyCookie" }) , UnmanagedType.CustomMarshaler }; + // TODO: When array support added add test for LPArray/ByValArray/SafeArray + } + + [Theory] + [MemberData(nameof(MarshalAsAttributeWithVariousFields))] + public void MarshalAsPseudoCustomAttributesTest(CustomAttributeBuilder attribute, UnmanagedType expectedType) + { + using (TempFile file = TempFile.Create()) + { + Type type = typeof(StructWithFields); + AssemblyBuilder ab = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod( + PopulateAssemblyName(), null, typeof(string), out MethodInfo saveMethod); + TypeBuilder tb = ab.DefineDynamicModule("Module").DefineType(type.FullName, type.Attributes, type.BaseType); + FieldInfo stringField = type.GetFields()[1]; + FieldBuilder fb = tb.DefineField(stringField.Name, stringField.FieldType, stringField.Attributes); + fb.SetCustomAttribute(attribute); + saveMethod.Invoke(ab, new object[] { file.Path }); + + Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path); + FieldInfo field = assemblyFromDisk.Modules.First().GetTypes()[0].GetFields()[0]; + CustomAttributeData attributeFromDisk = field.GetCustomAttributesData()[0]; + + Assert.Equal(1, field.GetCustomAttributesData().Count); + Assert.True((field.Attributes & FieldAttributes.HasFieldMarshal) != 0); + Assert.Equal(expectedType, (UnmanagedType)attributeFromDisk.ConstructorArguments[0].Value); + + switch (expectedType) + { + case UnmanagedType.CustomMarshaler: + Assert.Equal(typeof(EmptyTestClass).AssemblyQualifiedName, + attributeFromDisk.NamedArguments.First(na => na.MemberName == "MarshalType").TypedValue.Value); + Assert.Equal("MyCookie", attributeFromDisk.NamedArguments.First(na => na.MemberName == "MarshalCookie").TypedValue.Value); + break; + case UnmanagedType.ByValTStr: + Assert.Equal(256, attributeFromDisk.NamedArguments.First(na => na.MemberName == "SizeConst").TypedValue.Value); + break; + } + } + } + } +} diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTestsWithVariousTypes.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveWithVariousMembersTests.cs similarity index 62% rename from src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTestsWithVariousTypes.cs rename to src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveWithVariousMembersTests.cs index 22b85bc9693d96..bf256d909eb847 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTestsWithVariousTypes.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveWithVariousMembersTests.cs @@ -9,7 +9,7 @@ namespace System.Reflection.Emit.Tests { [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] - public class AssemblySaveTestsWithVariousTypes + public class AssemblySaveWithVariousMembersTests { private static readonly AssemblyName s_assemblyName = new AssemblyName("MyDynamicAssembly") { @@ -25,23 +25,9 @@ public void EmptyAssemblyAndModuleTest() using (TempFile file = TempFile.Create()) { Assembly assemblyFromDisk = WriteAndLoadAssembly(Type.EmptyTypes, file.Path); - AssemblyName aNameFromDisk = assemblyFromDisk.GetName(); - - // Test AssemblyName properties - Assert.Equal(s_assemblyName.Name, aNameFromDisk.Name); - Assert.Equal(s_assemblyName.Version, aNameFromDisk.Version); - Assert.Equal(s_assemblyName.CultureInfo, aNameFromDisk.CultureInfo); - Assert.Equal(s_assemblyName.CultureName, aNameFromDisk.CultureName); - Assert.Equal(s_assemblyName.ContentType, aNameFromDisk.ContentType); - // Runtime assemblies adding AssemblyNameFlags.PublicKey in Assembly.GetName() overloads - Assert.Equal(s_assemblyName.Flags | AssemblyNameFlags.PublicKey, aNameFromDisk.Flags); - Assert.Empty(assemblyFromDisk.GetTypes()); - - Module moduleFromDisk = assemblyFromDisk.Modules.FirstOrDefault(); - Assert.NotNull(moduleFromDisk); - Assert.Equal(s_assemblyName.Name, moduleFromDisk.ScopeName); - Assert.Empty(moduleFromDisk.GetTypes()); + Assert.Empty(assemblyFromDisk.GetTypes()); + AssemblyTools.AssertAssemblyNameAndModule(s_assemblyName, assemblyFromDisk.GetName(), assemblyFromDisk.Modules.FirstOrDefault()); } } @@ -86,51 +72,12 @@ private static void AssertTypesAndTypeMembers(Type[] types, Type[] typesFromDisk Type sourceType = types[i]; Type typeFromDisk = typesFromDisk[i]; - AssertTypeProperties(sourceType, typeFromDisk); - AssertMethods(sourceType.GetMethods(), typeFromDisk.GetMethods()); - AssertFields(sourceType.GetFields(), typeFromDisk.GetFields()); - } - } - - private static void AssertFields(FieldInfo[] declaredFields, FieldInfo[] fieldsFromDisk) - { - Assert.Equal(declaredFields.Length, fieldsFromDisk.Length); - - for (int j = 0; j < declaredFields.Length; j++) - { - FieldInfo sourceField = declaredFields[j]; - FieldInfo fieldFromDisk = fieldsFromDisk[j]; - - Assert.Equal(sourceField.Name, fieldFromDisk.Name); - Assert.Equal(sourceField.Attributes, fieldFromDisk.Attributes); - Assert.Equal(sourceField.FieldType.FullName, fieldFromDisk.FieldType.FullName); + AssemblyTools.AssertTypeProperties(sourceType, typeFromDisk); + AssemblyTools.AssertMethods(sourceType.GetMethods(), typeFromDisk.GetMethods()); + AssemblyTools.AssertFields(sourceType.GetFields(), typeFromDisk.GetFields()); } } - private static void AssertMethods(MethodInfo[] sourceMethods, MethodInfo[] methodsFromDisk) - { - Assert.Equal(sourceMethods.Length, methodsFromDisk.Length); - - for (int j = 0; j < sourceMethods.Length; j++) - { - MethodInfo sourceMethod = sourceMethods[j]; - MethodInfo methodFromDisk = methodsFromDisk[j]; - - Assert.Equal(sourceMethod.Name, methodFromDisk.Name); - Assert.Equal(sourceMethod.Attributes, methodFromDisk.Attributes); - Assert.Equal(sourceMethod.ReturnType.FullName, methodFromDisk.ReturnType.FullName); - } - } - - private static void AssertTypeProperties(Type sourceType, Type typeFromDisk) - { - Assert.Equal(sourceType.Name, typeFromDisk.Name); - Assert.Equal(sourceType.Namespace, typeFromDisk.Namespace); - Assert.Equal(sourceType.Attributes, typeFromDisk.Attributes); - Assert.Equal(sourceType.IsInterface, typeFromDisk.IsInterface); - Assert.Equal(sourceType.IsValueType, typeFromDisk.IsValueType); - } - [Theory] [MemberData(nameof(VariousInterfacesStructsTestData))] public void WriteAssemblyWithVariousTypesToStreamAndReadBackTest(Type[] types) @@ -149,9 +96,8 @@ public void CreateMembersThatUsesTypeLoadedFromCoreAssemblyTest() { using (TempFile file = TempFile.Create()) { - MethodInfo defineDynamicAssemblyMethod = AssemblyTools.PopulateMethods(typeof(string), out MethodInfo saveMethod); - AssemblyBuilder assemblyBuilder = (AssemblyBuilder)defineDynamicAssemblyMethod.Invoke(null, - new object[] { s_assemblyName, typeof(object).Assembly, null }); + AssemblyBuilder assemblyBuilder = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod( + s_assemblyName, null, typeof(string), out MethodInfo saveMethod); ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module"); TypeBuilder tb = mb.DefineType("TestInterface", TypeAttributes.Interface | TypeAttributes.Abstract); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblyTools.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblyTools.cs index b07c04b2ea755b..0cb5fe311d37a2 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblyTools.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblyTools.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.IO; +using System.Runtime.InteropServices; +using Xunit; namespace System.Reflection.Emit.Tests { @@ -10,23 +12,16 @@ internal static class AssemblyTools { internal static void WriteAssemblyToDisk(AssemblyName assemblyName, Type[] types, string fileLocation) { - WriteAssemblyToDisk(assemblyName, types, fileLocation, null); - } - - internal static void WriteAssemblyToDisk(AssemblyName assemblyName, Type[] types, string fileLocation, List assemblyAttributes) - { - MethodInfo defineDynamicAssemblyMethod = PopulateMethods(typeof(string), out MethodInfo saveMethod); + AssemblyBuilder assemblyBuilder = PopulateAssemblyBuilderAndSaveMethod( + assemblyName, null, typeof(string), out MethodInfo saveMethod); - AssemblyBuilder assemblyBuilder = (AssemblyBuilder)defineDynamicAssemblyMethod.Invoke(null, - new object[] { assemblyName, CoreMetadataAssemblyResolver.s_coreAssembly, assemblyAttributes }); ModuleBuilder mb = assemblyBuilder.DefineDynamicModule(assemblyName.Name); - - PopulateMembersForModule(types, mb); + PopulateMembersForModule(mb, types); saveMethod.Invoke(assemblyBuilder, new object[] { fileLocation }); } - private static void PopulateMembersForModule(Type[] types, ModuleBuilder mb) + private static void PopulateMembersForModule(ModuleBuilder mb, Type[] types) { foreach (Type type in types) { @@ -47,33 +42,27 @@ private static void PopulateMembersForModule(Type[] types, ModuleBuilder mb) internal static void WriteAssemblyToStream(AssemblyName assemblyName, Type[] types, Stream stream) { - WriteAssemblyToStream(assemblyName, types, stream, null); - } - - internal static void WriteAssemblyToStream(AssemblyName assemblyName, Type[] types, Stream stream, List? assemblyAttributes) - { - MethodInfo defineDynamicAssemblyMethod = PopulateMethods(typeof(Stream), out MethodInfo saveMethod); - - AssemblyBuilder assemblyBuilder = (AssemblyBuilder)defineDynamicAssemblyMethod.Invoke(null, - new object[] { assemblyName, CoreMetadataAssemblyResolver.s_coreAssembly, assemblyAttributes }); + AssemblyBuilder assemblyBuilder = PopulateAssemblyBuilderAndSaveMethod( + assemblyName, null, typeof(Stream), out MethodInfo saveMethod); ModuleBuilder mb = assemblyBuilder.DefineDynamicModule(assemblyName.Name); - - PopulateMembersForModule(types, mb); + PopulateMembersForModule(mb, types); saveMethod.Invoke(assemblyBuilder, new object[] { stream }); } - internal static MethodInfo PopulateMethods(Type parameterType, out MethodInfo saveMethod) + internal static AssemblyBuilder PopulateAssemblyBuilderAndSaveMethod(AssemblyName assemblyName, + List? assemblyAttributes, Type parameterType, out MethodInfo saveMethod) { - Type assemblyType = Type.GetType( - "System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit", - throwOnError: true)!; + Type assemblyType = Type.GetType("System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit", throwOnError: true)!; saveMethod = assemblyType.GetMethod("Save", BindingFlags.NonPublic | BindingFlags.Instance, new Type[] { parameterType }); - return assemblyType.GetMethod("DefinePersistedAssembly", BindingFlags.NonPublic | BindingFlags.Static, + MethodInfo defineDynamicAssemblyMethod = assemblyType.GetMethod("DefinePersistedAssembly", BindingFlags.NonPublic | BindingFlags.Static, new Type[] { typeof(AssemblyName), typeof(Assembly), typeof(List) }); + + return (AssemblyBuilder)defineDynamicAssemblyMethod.Invoke(null, + new object[] { assemblyName, CoreMetadataAssemblyResolver.s_coreAssembly, assemblyAttributes }); } internal static Assembly LoadAssemblyFromPath(string filePath) => @@ -81,6 +70,60 @@ internal static Assembly LoadAssemblyFromPath(string filePath) => internal static Assembly LoadAssemblyFromStream(Stream stream) => new MetadataLoadContext(new CoreMetadataAssemblyResolver()).LoadFromStream(stream); + + internal static void AssertAssemblyNameAndModule(AssemblyName sourceAName, AssemblyName aNameFromDisk, Module moduleFromDisk) + { + // Runtime assemblies adding AssemblyNameFlags.PublicKey in Assembly.GetName() overloads + Assert.Equal(sourceAName.Flags | AssemblyNameFlags.PublicKey, aNameFromDisk.Flags); + Assert.Equal(sourceAName.Name, aNameFromDisk.Name); + Assert.Equal(sourceAName.Version, aNameFromDisk.Version); + Assert.Equal(sourceAName.CultureInfo, aNameFromDisk.CultureInfo); + Assert.Equal(sourceAName.CultureName, aNameFromDisk.CultureName); + Assert.Equal(sourceAName.ContentType, aNameFromDisk.ContentType); + + Assert.NotNull(moduleFromDisk); + Assert.Equal(sourceAName.Name, moduleFromDisk.ScopeName); + Assert.Empty(moduleFromDisk.GetTypes()); + } + + internal static void AssertTypeProperties(Type sourceType, Type typeFromDisk) + { + Assert.Equal(sourceType.Name, typeFromDisk.Name); + Assert.Equal(sourceType.Namespace, typeFromDisk.Namespace); + Assert.Equal(sourceType.Attributes, typeFromDisk.Attributes); + Assert.Equal(sourceType.IsInterface, typeFromDisk.IsInterface); + Assert.Equal(sourceType.IsValueType, typeFromDisk.IsValueType); + } + + internal static void AssertFields(FieldInfo[] declaredFields, FieldInfo[] fieldsFromDisk) + { + Assert.Equal(declaredFields.Length, fieldsFromDisk.Length); + + for (int j = 0; j < declaredFields.Length; j++) + { + FieldInfo sourceField = declaredFields[j]; + FieldInfo fieldFromDisk = fieldsFromDisk[j]; + + Assert.Equal(sourceField.Name, fieldFromDisk.Name); + Assert.Equal(sourceField.Attributes, fieldFromDisk.Attributes); + Assert.Equal(sourceField.FieldType.FullName, fieldFromDisk.FieldType.FullName); + } + } + + internal static void AssertMethods(MethodInfo[] sourceMethods, MethodInfo[] methodsFromDisk) + { + Assert.Equal(sourceMethods.Length, methodsFromDisk.Length); + + for (int j = 0; j < sourceMethods.Length; j++) + { + MethodInfo sourceMethod = sourceMethods[j]; + MethodInfo methodFromDisk = methodsFromDisk[j]; + + Assert.Equal(sourceMethod.Name, methodFromDisk.Name); + Assert.Equal(sourceMethod.Attributes, methodFromDisk.Attributes); + Assert.Equal(sourceMethod.ReturnType.FullName, methodFromDisk.ReturnType.FullName); + } + } } // The resolver copied from MLC tests diff --git a/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj b/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj index f10f0a08c4e4bc..f672dc37d9e828 100644 --- a/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj +++ b/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj @@ -62,7 +62,8 @@ - + + diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.Mono.cs index 494a2bc3b86f6f..28cbe9e7cb2a84 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.Mono.cs @@ -77,13 +77,12 @@ internal object Invoke() return result; } - internal CustomAttributeBuilder(ConstructorInfo con, byte[] binaryAttribute) + internal CustomAttributeBuilder(ConstructorInfo con, ReadOnlySpan binaryAttribute) { ArgumentNullException.ThrowIfNull(con); - ArgumentNullException.ThrowIfNull(binaryAttribute); ctor = con; - data = (byte[])binaryAttribute.Clone(); + data = binaryAttribute.ToArray(); /* should we check that the user supplied data is correct? */ } @@ -268,7 +267,7 @@ private void Initialize(ConstructorInfo con, object?[] constructorArgs, } /* helper methods */ - internal static int decode_len(byte[] data, int pos, out int rpos) + internal static int decode_len(ReadOnlySpan data, int pos, out int rpos) { int len; if ((data[pos] & 0x80) == 0) @@ -289,9 +288,9 @@ internal static int decode_len(byte[] data, int pos, out int rpos) return len; } - internal static string string_from_bytes(byte[] data, int pos, int len) + internal static string string_from_bytes(ReadOnlySpan data, int pos, int len) { - return Text.Encoding.UTF8.GetString(data, pos, len); + return Text.Encoding.UTF8.GetString(data.Slice(pos, len)); } internal static string? decode_string(byte[] data, int pos, out int rpos) @@ -454,7 +453,7 @@ private static Type elementTypeToType(int elementType) => _ => throw new Exception(SR.Format(SR.ArgumentException_InvalidTypeArgument, elementType)), }; - private static object? decode_cattr_value(Type t, byte[] data, int pos, out int rpos) + private static object? decode_cattr_value(Type t, ReadOnlySpan data, int pos, out int rpos) { switch (Type.GetTypeCode(t)) { @@ -494,14 +493,19 @@ internal struct CustomAttributeInfo public object?[] namedParamValues; } + internal static CustomAttributeInfo decode_cattr(CustomAttributeBuilder customBuilder) + { + byte[] data = customBuilder.Data; + ConstructorInfo ctor = customBuilder.Ctor; + return decode_cattr(ctor, data); + } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2057:UnrecognizedReflectionPattern", Justification = "Types referenced from custom attributes are preserved")] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification = "Types referenced from custom attributes are preserved")] - internal static CustomAttributeInfo decode_cattr(CustomAttributeBuilder customBuilder) + internal static CustomAttributeInfo decode_cattr(ConstructorInfo ctor, ReadOnlySpan data) { - byte[] data = customBuilder.Data; - ConstructorInfo ctor = customBuilder.Ctor; int pos; CustomAttributeInfo info = default; diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.Mono.cs index a5bfdaabee1f33..32cbacfc6a4df4 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.Mono.cs @@ -297,8 +297,9 @@ internal static AssemblyBuilder InternalDefineDynamicAssembly( public override bool IsCollectible => access == (uint)AssemblyBuilderAccess.RunAndCollect; - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { + CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute); if (cattrs != null) { CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1]; @@ -315,11 +316,6 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil UpdateNativeCustomAttributes(this); } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) - { - SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute)); - } - /*Warning, @typeArguments must be a mscorlib internal array. So make a copy before passing it in*/ internal static Type MakeGenericType(Type gtd, Type[] typeArguments) => new TypeBuilderInstantiation(gtd, typeArguments); 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 f9939d27b3183b..83c62a8e9817ac 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 @@ -37,6 +37,7 @@ using System.Globalization; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +using System.Buffers.Binary; namespace System.Reflection.Emit { @@ -254,20 +255,16 @@ protected override ILGenerator GetILGeneratorCore(int streamSize) return ilgen; } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { - ArgumentNullException.ThrowIfNull(customBuilder); - - string? attrname = customBuilder.Ctor.ReflectedType!.FullName; + string? attrname = con.ReflectedType!.FullName; if (attrname == "System.Runtime.CompilerServices.MethodImplAttribute") { - byte[] data = customBuilder.Data; - int impla; // the (stupid) ctor takes a short or an int ... - impla = (int)data[2]; - impla |= ((int)data[3]) << 8; + int impla = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(2)); SetImplementationFlags((MethodImplAttributes)impla); return; } + CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute); if (cattrs != null) { CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1]; @@ -282,14 +279,6 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil } } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) - { - ArgumentNullException.ThrowIfNull(con); - ArgumentNullException.ThrowIfNull(binaryAttribute); - - SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute)); - } - protected override void SetImplementationFlagsCore(MethodImplAttributes attributes) { if (type.is_created) diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEnumBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEnumBuilder.Mono.cs index ab54737e986dcb..b417c32f06abae 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEnumBuilder.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEnumBuilder.Mono.cs @@ -447,14 +447,9 @@ public override Type MakePointerType() return SymbolType.FormCompoundType("*", this, 0)!; } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { - _tb.SetCustomAttribute(customBuilder); - } - - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) - { - SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute)); + _tb.SetCustomAttribute(con, binaryAttribute); } internal override bool IsUserType diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEventBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEventBuilder.Mono.cs index 8ff4a3df89eac5..5cbfea669f365d 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEventBuilder.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeEventBuilder.Mono.cs @@ -106,15 +106,16 @@ protected override void SetRemoveOnMethodCore(MethodBuilder mdBuilder) remove_method = mdBuilder; } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { RejectIfCreated(); - string? attrname = customBuilder.Ctor.ReflectedType!.FullName; + string? attrname = con.ReflectedType!.FullName; if (attrname == "System.Runtime.CompilerServices.SpecialNameAttribute") { attrs |= EventAttributes.SpecialName; return; } + CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute); if (cattrs != null) { CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1]; @@ -129,11 +130,6 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil } } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) - { - SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute)); - } - private void RejectIfCreated() { if (typeb.is_created) diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeFieldBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeFieldBuilder.Mono.cs index db8d805de1646b..68f4c7b2bbf74b 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeFieldBuilder.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeFieldBuilder.Mono.cs @@ -37,6 +37,7 @@ using System.Globalization; using System.Runtime.InteropServices; using System.Diagnostics.CodeAnalysis; +using System.Buffers.Binary; namespace System.Reflection.Emit { @@ -174,18 +175,14 @@ protected override void SetConstantCore(object? defaultValue) def_value = defaultValue; } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { RejectIfCreated(); - - string? attrname = customBuilder.Ctor.ReflectedType!.FullName; + CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute); + string? attrname = con.ReflectedType!.FullName; if (attrname == "System.Runtime.InteropServices.FieldOffsetAttribute") { - byte[] data = customBuilder.Data; - offset = (int)data[2]; - offset |= ((int)data[3]) << 8; - offset |= ((int)data[4]) << 16; - offset |= ((int)data[5]) << 24; + offset = BinaryPrimitives.ReadInt32LittleEndian(binaryAttribute.Slice(2)); return; } #pragma warning disable SYSLIB0050 // FieldAttributes.NotSerialized is obsolete @@ -221,12 +218,6 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil } } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) - { - RejectIfCreated(); - SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute)); - } - protected override void SetOffsetCore(int iOffset) { RejectIfCreated(); diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeGenericTypeParameterBuilder.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeGenericTypeParameterBuilder.cs index a1f176127f97f8..27e0d2e9975561 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeGenericTypeParameterBuilder.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeGenericTypeParameterBuilder.cs @@ -424,8 +424,9 @@ public override MethodBase? DeclaringMethod get { return mbuilder; } } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { + CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute); if (cattrs != null) { CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1]; @@ -440,12 +441,6 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil } } - // FIXME: "unverified implementation" - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) - { - SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute)); - } - private static NotSupportedException not_supported() { return new NotSupportedException(); 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 80e8352d04b40e..cdae1832367f8c 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 @@ -34,6 +34,7 @@ // #if MONO_FEATURE_SRE +using System.Buffers.Binary; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; @@ -381,20 +382,17 @@ internal void ResolveUserTypes() } } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { - switch (customBuilder.Ctor.ReflectedType!.FullName) + switch (con.ReflectedType!.FullName) { case "System.Runtime.CompilerServices.MethodImplAttribute": - byte[] data = customBuilder.Data; - int impla; // the (stupid) ctor takes a short or an int ... - impla = (int)data[2]; - impla |= ((int)data[3]) << 8; + int impla = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(2)); iattrs |= (MethodImplAttributes)impla; return; case "System.Runtime.InteropServices.DllImportAttribute": - CustomAttributeBuilder.CustomAttributeInfo attr = CustomAttributeBuilder.decode_cattr(customBuilder); + CustomAttributeBuilder.CustomAttributeInfo attr = CustomAttributeBuilder.decode_cattr(con, binaryAttribute); bool preserveSig = true; /* @@ -453,6 +451,7 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil break; } + CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute); if (cattrs != null) { CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1]; @@ -467,11 +466,6 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil } } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) - { - SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute)); - } - protected override void SetImplementationFlagsCore(MethodImplAttributes attributes) { RejectIfCreated(); diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeModuleBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeModuleBuilder.Mono.cs index a6ab47cae28d3e..85e98ea5b84a4c 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeModuleBuilder.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeModuleBuilder.Mono.cs @@ -426,8 +426,9 @@ internal int get_next_table_index(int table, int count) return index; } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { + CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute); if (cattrs != null) { CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1]; @@ -441,11 +442,6 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil cattrs[0] = customBuilder; } } - - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) - { - SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute)); - } /* internal ISymbolDocumentWriter? DefineDocument (string url, Guid language, Guid languageVendor, Guid documentType) { diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimePropertyBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimePropertyBuilder.Mono.cs index 80c8d942ccd68f..25dbb485d23c3e 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimePropertyBuilder.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimePropertyBuilder.Mono.cs @@ -159,16 +159,18 @@ protected override void SetConstantCore(object? defaultValue) def_value = defaultValue; } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) { typeb.check_not_created(); - string? attrname = customBuilder.Ctor.ReflectedType!.FullName; + string? attrname = con.ReflectedType!.FullName; if (attrname == "System.Runtime.CompilerServices.SpecialNameAttribute") { attrs |= PropertyAttributes.SpecialName; return; } + CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute); + if (cattrs != null) { CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1]; @@ -183,11 +185,6 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil } } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) - { - SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute)); - } - protected override void SetGetMethodCore(MethodBuilder mdBuilder) { typeb.check_not_created(); diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeTypeBuilder.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeTypeBuilder.Mono.cs index 98670c99f16313..469f9efebb744b 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeTypeBuilder.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeTypeBuilder.Mono.cs @@ -34,6 +34,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System.Buffers.Binary; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -1411,15 +1412,19 @@ public override RuntimeTypeHandle TypeHandle } } - protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder) + internal void SetCustomAttribute(ConstructorInfo con, ReadOnlySpan binaryAttribute) { - string? attrname = customBuilder.Ctor.ReflectedType!.FullName; + SetCustomAttributeCore(con, binaryAttribute); + } + + protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute) + { + string? attrname = con.ReflectedType!.FullName; if (attrname == "System.Runtime.InteropServices.StructLayoutAttribute") { - byte[] data = customBuilder.Data; int layout_kind; /* the (stupid) ctor takes a short or an int ... */ - layout_kind = (int)data[2]; - layout_kind |= ((int)data[3]) << 8; + layout_kind = (int)binaryAttribute[2]; + layout_kind |= ((int)binaryAttribute[3]) << 8; attrs &= ~TypeAttributes.LayoutMask; attrs |= ((LayoutKind)layout_kind) switch { @@ -1429,38 +1434,36 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil _ => throw new Exception(SR.Argument_InvalidKindOfTypeForCA), // we should ignore it since it can be any value anyway... }; - Type ctor_type = customBuilder.Ctor is RuntimeConstructorBuilder builder ? builder.parameters![0] : customBuilder.Ctor.GetParametersInternal()[0].ParameterType; + Type ctor_type = con is RuntimeConstructorBuilder builder ? builder.parameters![0] : con.GetParametersInternal()[0].ParameterType; int pos = 6; if (ctor_type.FullName == "System.Int16") pos = 4; - int nnamed = (int)data[pos++]; - nnamed |= ((int)data[pos++]) << 8; + int nnamed = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(pos++)); + pos++; for (int i = 0; i < nnamed; ++i) { //byte named_type = data [pos++]; pos++; - byte type = data[pos++]; + byte type = binaryAttribute[pos++]; int len; string named_name; if (type == 0x55) { - len = CustomAttributeBuilder.decode_len(data, pos, out pos); + len = CustomAttributeBuilder.decode_len(binaryAttribute, pos, out pos); //string named_typename = - CustomAttributeBuilder.string_from_bytes(data, pos, len); + CustomAttributeBuilder.string_from_bytes(binaryAttribute, pos, len); pos += len; // FIXME: Check that 'named_type' and 'named_typename' match, etc. // See related code/FIXME in mono/mono/metadata/reflection.c } - len = CustomAttributeBuilder.decode_len(data, pos, out pos); - named_name = CustomAttributeBuilder.string_from_bytes(data, pos, len); + len = CustomAttributeBuilder.decode_len(binaryAttribute, pos, out pos); + named_name = CustomAttributeBuilder.string_from_bytes(binaryAttribute, pos, len); pos += len; /* all the fields are integers in StructLayout */ - int value = (int)data[pos++]; - value |= ((int)data[pos++]) << 8; - value |= ((int)data[pos++]) << 16; - value |= ((int)data[pos++]) << 24; + int value = BinaryPrimitives.ReadInt32LittleEndian(binaryAttribute.Slice(pos++)); + pos += 3; switch (named_name) { case "CharSet": @@ -1520,6 +1523,8 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil is_byreflike_set = 1; } + CustomAttributeBuilder customBuilder = new CustomAttributeBuilder(con, binaryAttribute); + if (cattrs != null) { CustomAttributeBuilder[] new_array = new CustomAttributeBuilder[cattrs.Length + 1]; @@ -1534,11 +1539,6 @@ protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuil } } - protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) - { - SetCustomAttributeCore(new CustomAttributeBuilder(con, binaryAttribute)); - } - protected override EventBuilder DefineEventCore(string name, EventAttributes attributes, Type eventtype) { check_name(nameof(name), name);