Skip to content

AssemblyBuilder.Save add custom attributes handling. #84580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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) :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ public override Assembly GetSatelliteAssembly(CultureInfo culture, Version? vers
/// <summary>
/// Use this function if client decides to form the custom attribute blob themselves.
/// </summary>
protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
lock (SyncRoot)
{
Expand All @@ -299,16 +299,5 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binar
binaryAttribute);
}
}

/// <summary>
/// Use this function if client wishes to build CustomAttribute using CustomAttributeBuilder.
/// </summary>
protected override void SetCustomAttributeCore(CustomAttributeBuilder customBuilder)
{
lock (SyncRoot)
{
customBuilder.CreateCustomAttribute(_manifestModuleBuilder, AssemblyDefToken);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,26 +274,18 @@ 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<byte> 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;

// Return the class that was used to obtain this field.

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)
{
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> binaryAttribute)
{
m_type.ThrowIfCreated();

Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> binaryAttribute)
{
RuntimeModuleBuilder moduleBuilder = (RuntimeModuleBuilder)m_typeBuilder.Module;

Expand All @@ -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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ internal Module GetModule()
return GetModuleBuilder();
}

protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
ThrowIfGeneric();
RuntimeTypeBuilder.DefineCustomAttribute(m_module, MetadataToken,
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> binaryAttribute)
{
RuntimeTypeBuilder.DefineCustomAttribute(
this,
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> binaryAttribute)
{
m_containingType.ThrowIfCreated();
RuntimeTypeBuilder.DefineCustomAttribute(
Expand All @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> binaryAttribute)
{
ArgumentNullException.ThrowIfNull(con);
ArgumentNullException.ThrowIfNull(binaryAttribute);

m_con = con;
m_binaryAttribute = binaryAttribute;
m_binaryAttribute = binaryAttribute.ToArray();
Copy link
Member

Choose a reason for hiding this comment

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

This is introducing an extra array copy. Do you remember whether this regression was considered during the API review discussion that proposed changing the argument type to ReadOnlySpan?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you remember whether this regression was considered during the API review discussion that proposed changing the argument type to ReadOnlySpan?

No, I don't think so, there were not much discussion about this change, quickly agreed for this update. Would you suggest to keep the SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute) for now?

Copy link
Member

Choose a reason for hiding this comment

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

I think that the extra copy is fine, it is just something that I have noticed and that I did not expect. I do not have a strong opinion about it. What do you think?

Copy link
Contributor Author

@buyaa-n buyaa-n Apr 17, 2023

Choose a reason for hiding this comment

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

I think this path would be used rarely (attributes for generic type parameter) so probably fine, but for the new assembly builder implementation we are creating this copy for each attribute:


I think I can workaround that to keep the BlobHandle of the ReadOnlySpan<byte> instead of byte[] in CustomAttributeWrapper. But that needs #81059 merged and a public API for ReadOnlySpan<byte> overload is added

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added TODO for using BlobHandle instead of byte[].

There is similar allocation added in mono:

It is OK in case the SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) overload used directly as previously it was also cloning the byte array but as you know if the SetCustomAttribute(CustomAttributeBuilder customBuilder) overload is used it will call SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data) and going to create another copy ...

}

public CustAttr(CustomAttributeBuilder customBuilder)
Expand Down Expand Up @@ -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<byte> attr, int attrLength);

internal static void DefineCustomAttribute(RuntimeModuleBuilder module, int tkAssociate, int tkConstructor,
byte[]? attr)
ReadOnlySpan<byte> 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)]
Expand Down Expand Up @@ -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<byte> binaryAttribute)
{
CustAttr ca = new CustAttr(con, binaryAttribute);

Expand Down Expand Up @@ -1858,14 +1849,14 @@ internal int TypeToken
}
}

protected override void SetCustomAttributeCore(ConstructorInfo con, byte[] binaryAttribute)
internal void SetCustomAttribute(ConstructorInfo con, ReadOnlySpan<byte> 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<byte> binaryAttribute)
{
customBuilder.CreateCustomAttribute(m_module, m_tdType);
DefineCustomAttribute(m_module, m_tdType, m_module.GetMethodMetadataToken(con), binaryAttribute);
}

#endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> binaryAttribute);

public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
=> SetCustomAttributeCore(customBuilder);

protected abstract void SetCustomAttributeCore(CustomAttributeBuilder customBuilder);
=> SetCustomAttributeCore(customBuilder.Ctor, customBuilder.Data);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> 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);

Expand Down
Loading