From 1a820cbf867abfa68acc5d7fb9c925a47132f36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 16 Apr 2024 16:45:11 +0900 Subject: [PATCH] Generate custom attributes from metadata instead of type system (#100763) Fixes #100688 Fixes a bit more than just what was reported (see the test). We were losing type information in `attribute.DecodeValue` and could no longer distinguish between `new object[] { SomeEnum.Val }` and `new SomeEnum[] { SomeEnum.Val }`. The fix required a complete rewrite of attribute emission using the more low level API. Cc @dotnet/ilc-contrib --- .../src/CompatibilitySuppressions.xml | 4 +- .../MetadataReaderExtensions.NativeFormat.cs | 8 +- .../NativeFormat/Generator/SchemaDef.cs | 14 +- .../NativeFormat/MdBinaryReaderGen.cs | 18 +- .../NativeFormatReaderCommonGen.cs | 16 +- .../NativeFormat/NativeFormatReaderGen.cs | 318 +++++++++--------- .../Metadata/Transform.CustomAttribute.cs | 288 +++++++++------- .../NativeFormat/Writer/MdBinaryWriterGen.cs | 44 +-- .../Writer/NativeFormatWriterGen.cs | 156 ++++----- .../CustomAttributeTests.cs | 38 +++ 10 files changed, 492 insertions(+), 412 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml index 9d09ab7e105928..770514a671adfc 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml @@ -55,11 +55,11 @@ CP0001 - T:Internal.Metadata.NativeFormat.ConstantBoxedEnumValue + T:Internal.Metadata.NativeFormat.ConstantEnumValue CP0001 - T:Internal.Metadata.NativeFormat.ConstantBoxedEnumValueHandle + T:Internal.Metadata.NativeFormat.ConstantEnumValueHandle CP0001 diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs index eb4289695020ec..e5f82238f0b51e 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs @@ -141,9 +141,9 @@ public static bool IsConstructor(ref Method method, MetadataReader reader) return nameHandle.StringEquals(ConstructorInfo.ConstructorName, reader) || nameHandle.StringEquals(ConstructorInfo.TypeConstructorName, reader); } - private static Exception ParseBoxedEnumConstantValue(this ConstantBoxedEnumValueHandle handle, MetadataReader reader, out object value) + private static Exception ParseEnumConstantValue(this ConstantEnumValueHandle handle, MetadataReader reader, out object value) { - ConstantBoxedEnumValue record = handle.GetConstantBoxedEnumValue(reader); + ConstantEnumValue record = handle.GetConstantEnumValue(reader); Exception? exception = null; Type? enumType = record.Type.TryResolve(reader, new TypeContext(null, null), ref exception)?.ToType(); @@ -317,9 +317,9 @@ public static Exception TryParseConstantValue(this Handle handle, MetadataReader case HandleType.ConstantReferenceValue: value = null; return null; - case HandleType.ConstantBoxedEnumValue: + case HandleType.ConstantEnumValue: { - return handle.ToConstantBoxedEnumValueHandle(reader).ParseBoxedEnumConstantValue(reader, out value); + return handle.ToConstantEnumValueHandle(reader).ParseEnumConstantValue(reader, out value); } default: { diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs index daea57e6e4a1b2..371b9488a7d396 100644 --- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs +++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs @@ -315,6 +315,13 @@ from primitiveType in PrimitiveTypes members: new MemberDef[] { new MemberDef(name: "Value", typeName: "string") } + ), + new RecordDef( + name: "ConstantEnumValue", + members: new MemberDef[] { + new MemberDef("Value", EnumConstantValue, MemberDefFlags.RecordRef | MemberDefFlags.Child), + new MemberDef("Type", TypeDefOrRefOrSpec, MemberDefFlags.RecordRef) + } ) } ) @@ -630,13 +637,6 @@ from primitiveType in PrimitiveTypes new MemberDef("Value", TypeDefOrRefOrSpecOrConstant, MemberDefFlags.RecordRef), } ), - new RecordDef( - name: "ConstantBoxedEnumValue", - members: new MemberDef[] { - new MemberDef("Value", EnumConstantValue, MemberDefFlags.RecordRef | MemberDefFlags.Child), - new MemberDef("Type", TypeDefOrRefOrSpec, MemberDefFlags.RecordRef) - } - ), new RecordDef( name: "GenericParameter", members: new MemberDef[] { diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/MdBinaryReaderGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/MdBinaryReaderGen.cs index bbac55d7083047..6f0d97a9c38834 100644 --- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/MdBinaryReaderGen.cs +++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/MdBinaryReaderGen.cs @@ -300,15 +300,6 @@ public static uint Read(this NativeReader reader, uint offset, out ConstantBoole return offset; } // Read - public static uint Read(this NativeReader reader, uint offset, out ConstantBoxedEnumValueHandle handle) - { - uint value; - offset = reader.DecodeUnsigned(offset, out value); - handle = new ConstantBoxedEnumValueHandle((int)value); - handle._Validate(); - return offset; - } // Read - public static uint Read(this NativeReader reader, uint offset, out ConstantByteArrayHandle handle) { uint value; @@ -372,6 +363,15 @@ public static uint Read(this NativeReader reader, uint offset, out ConstantEnumA return offset; } // Read + public static uint Read(this NativeReader reader, uint offset, out ConstantEnumValueHandle handle) + { + uint value; + offset = reader.DecodeUnsigned(offset, out value); + handle = new ConstantEnumValueHandle((int)value); + handle._Validate(); + return offset; + } // Read + public static uint Read(this NativeReader reader, uint offset, out ConstantHandleArrayHandle handle) { uint value; diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs index bb7fefd7816ced..a9359f373de576 100644 --- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs +++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs @@ -94,14 +94,14 @@ public enum HandleType : byte ByReferenceSignature = 0x2, ConstantBooleanArray = 0x3, ConstantBooleanValue = 0x4, - ConstantBoxedEnumValue = 0x5, - ConstantByteArray = 0x6, - ConstantByteValue = 0x7, - ConstantCharArray = 0x8, - ConstantCharValue = 0x9, - ConstantDoubleArray = 0xa, - ConstantDoubleValue = 0xb, - ConstantEnumArray = 0xc, + ConstantByteArray = 0x5, + ConstantByteValue = 0x6, + ConstantCharArray = 0x7, + ConstantCharValue = 0x8, + ConstantDoubleArray = 0x9, + ConstantDoubleValue = 0xa, + ConstantEnumArray = 0xb, + ConstantEnumValue = 0xc, ConstantHandleArray = 0xd, ConstantInt16Array = 0xe, ConstantInt16Value = 0xf, diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs index 7bf0d91f44e556..3fe7c55c0c2b9c 100644 --- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs +++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs @@ -501,130 +501,6 @@ public override string ToString() } // ToString } // ConstantBooleanValueHandle -#if SYSTEM_PRIVATE_CORELIB - [CLSCompliant(false)] -#endif - public partial struct ConstantBoxedEnumValue - { - internal MetadataReader _reader; - internal ConstantBoxedEnumValueHandle _handle; - - public ConstantBoxedEnumValueHandle Handle - { - get - { - return _handle; - } - } // Handle - /// One of: ConstantByteValue, ConstantSByteValue, ConstantInt16Value, ConstantUInt16Value, ConstantInt32Value, ConstantUInt32Value, ConstantInt64Value, ConstantUInt64Value - - public Handle Value - { - get - { - return _value; - } - } // Value - - internal Handle _value; - /// One of: TypeDefinition, TypeReference, TypeSpecification - - public Handle Type - { - get - { - return _type; - } - } // Type - - internal Handle _type; - } // ConstantBoxedEnumValue - -#if SYSTEM_PRIVATE_CORELIB - [CLSCompliant(false)] -#endif - public partial struct ConstantBoxedEnumValueHandle - { - public override bool Equals(object obj) - { - if (obj is ConstantBoxedEnumValueHandle) - return _value == ((ConstantBoxedEnumValueHandle)obj)._value; - else if (obj is Handle) - return _value == ((Handle)obj)._value; - else - return false; - } // Equals - - public bool Equals(ConstantBoxedEnumValueHandle handle) - { - return _value == handle._value; - } // Equals - - public bool Equals(Handle handle) - { - return _value == handle._value; - } // Equals - - public override int GetHashCode() - { - return (int)_value; - } // GetHashCode - - internal int _value; - - internal ConstantBoxedEnumValueHandle(Handle handle) : this(handle._value) - { - } - - internal ConstantBoxedEnumValueHandle(int value) - { - HandleType hType = (HandleType)(value >> 24); - Debug.Assert(hType == 0 || hType == HandleType.ConstantBoxedEnumValue || hType == HandleType.Null); - _value = (value & 0x00FFFFFF) | (((int)HandleType.ConstantBoxedEnumValue) << 24); - _Validate(); - } - - public static implicit operator Handle(ConstantBoxedEnumValueHandle handle) - { - return new Handle(handle._value); - } // Handle - - internal int Offset - { - get - { - return (this._value & 0x00FFFFFF); - } - } // Offset - - public ConstantBoxedEnumValue GetConstantBoxedEnumValue(MetadataReader reader) - { - return reader.GetConstantBoxedEnumValue(this); - } // GetConstantBoxedEnumValue - - public bool IsNull(MetadataReader reader) - { - return reader.IsNull(this); - } // IsNull - - public Handle ToHandle(MetadataReader reader) - { - return reader.ToHandle(this); - } // ToHandle - - [System.Diagnostics.Conditional("DEBUG")] - internal void _Validate() - { - if ((HandleType)((_value & 0xFF000000) >> 24) != HandleType.ConstantBoxedEnumValue) - throw new ArgumentException(); - } // _Validate - - public override string ToString() - { - return string.Format("{0:X8}", _value); - } // ToString - } // ConstantBoxedEnumValueHandle - #if SYSTEM_PRIVATE_CORELIB [CLSCompliant(false)] #endif @@ -1419,6 +1295,128 @@ public override string ToString() } // ToString } // ConstantEnumArrayHandle +#if SYSTEM_PRIVATE_CORELIB + [CLSCompliant(false)] +#endif + public partial struct ConstantEnumValue + { + internal MetadataReader _reader; + internal ConstantEnumValueHandle _handle; + + public ConstantEnumValueHandle Handle + { + get + { + return _handle; + } + } // Handle + + public Handle Value + { + get + { + return _value; + } + } // Value + + internal Handle _value; + + public Handle Type + { + get + { + return _type; + } + } // Type + + internal Handle _type; + } // ConstantEnumValue + +#if SYSTEM_PRIVATE_CORELIB + [CLSCompliant(false)] +#endif + public partial struct ConstantEnumValueHandle + { + public override bool Equals(object obj) + { + if (obj is ConstantEnumValueHandle) + return _value == ((ConstantEnumValueHandle)obj)._value; + else if (obj is Handle) + return _value == ((Handle)obj)._value; + else + return false; + } // Equals + + public bool Equals(ConstantEnumValueHandle handle) + { + return _value == handle._value; + } // Equals + + public bool Equals(Handle handle) + { + return _value == handle._value; + } // Equals + + public override int GetHashCode() + { + return (int)_value; + } // GetHashCode + + internal int _value; + + internal ConstantEnumValueHandle(Handle handle) : this(handle._value) + { + } + + internal ConstantEnumValueHandle(int value) + { + HandleType hType = (HandleType)(value >> 24); + Debug.Assert(hType == 0 || hType == HandleType.ConstantEnumValue || hType == HandleType.Null); + _value = (value & 0x00FFFFFF) | (((int)HandleType.ConstantEnumValue) << 24); + _Validate(); + } + + public static implicit operator Handle(ConstantEnumValueHandle handle) + { + return new Handle(handle._value); + } // Handle + + internal int Offset + { + get + { + return (this._value & 0x00FFFFFF); + } + } // Offset + + public ConstantEnumValue GetConstantEnumValue(MetadataReader reader) + { + return reader.GetConstantEnumValue(this); + } // GetConstantEnumValue + + public bool IsNull(MetadataReader reader) + { + return reader.IsNull(this); + } // IsNull + + public Handle ToHandle(MetadataReader reader) + { + return reader.ToHandle(this); + } // ToHandle + + [System.Diagnostics.Conditional("DEBUG")] + internal void _Validate() + { + if ((HandleType)((_value & 0xFF000000) >> 24) != HandleType.ConstantEnumValue) + throw new ArgumentException(); + } // _Validate + + public override string ToString() + { + return string.Format("{0:X8}", _value); + } // ToString + } // ConstantEnumValueHandle + #if SYSTEM_PRIVATE_CORELIB [CLSCompliant(false)] #endif @@ -3676,7 +3674,7 @@ public Handle Constructor } // Constructor internal Handle _constructor; - /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value + /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantEnumValue, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value public HandleCollection FixedArguments { @@ -3982,7 +3980,7 @@ public FieldSignatureHandle Signature } // Signature internal FieldSignatureHandle _signature; - /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value + /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantEnumValue, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value public Handle DefaultValue { @@ -5487,7 +5485,7 @@ public Handle Type } // Type internal Handle _type; - /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value + /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantEnumValue, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value public Handle Value { @@ -5906,7 +5904,7 @@ public ConstantStringValueHandle Name } // Name internal ConstantStringValueHandle _name; - /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value + /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantEnumValue, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value public Handle DefaultValue { @@ -6182,7 +6180,7 @@ public MethodSemanticsHandleCollection MethodSemantics } // MethodSemantics internal MethodSemanticsHandleCollection _methodSemantics; - /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value + /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantEnumValue, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value public Handle DefaultValue { @@ -9833,11 +9831,6 @@ public ConstantBooleanValueHandle ToConstantBooleanValueHandle(MetadataReader re return new ConstantBooleanValueHandle(this); } // ToConstantBooleanValueHandle - public ConstantBoxedEnumValueHandle ToConstantBoxedEnumValueHandle(MetadataReader reader) - { - return new ConstantBoxedEnumValueHandle(this); - } // ToConstantBoxedEnumValueHandle - public ConstantByteArrayHandle ToConstantByteArrayHandle(MetadataReader reader) { return new ConstantByteArrayHandle(this); @@ -9873,6 +9866,11 @@ public ConstantEnumArrayHandle ToConstantEnumArrayHandle(MetadataReader reader) return new ConstantEnumArrayHandle(this); } // ToConstantEnumArrayHandle + public ConstantEnumValueHandle ToConstantEnumValueHandle(MetadataReader reader) + { + return new ConstantEnumValueHandle(this); + } // ToConstantEnumValueHandle + public ConstantHandleArrayHandle ToConstantHandleArrayHandle(MetadataReader reader) { return new ConstantHandleArrayHandle(this); @@ -10246,17 +10244,6 @@ public ConstantBooleanValue GetConstantBooleanValue(ConstantBooleanValueHandle h return record; } // GetConstantBooleanValue - public ConstantBoxedEnumValue GetConstantBoxedEnumValue(ConstantBoxedEnumValueHandle handle) - { - ConstantBoxedEnumValue record; - record._reader = this; - record._handle = handle; - var offset = (uint)handle.Offset; - offset = _streamReader.Read(offset, out record._value); - offset = _streamReader.Read(offset, out record._type); - return record; - } // GetConstantBoxedEnumValue - public ConstantByteArray GetConstantByteArray(ConstantByteArrayHandle handle) { ConstantByteArray record; @@ -10328,6 +10315,17 @@ public ConstantEnumArray GetConstantEnumArray(ConstantEnumArrayHandle handle) return record; } // GetConstantEnumArray + public ConstantEnumValue GetConstantEnumValue(ConstantEnumValueHandle handle) + { + ConstantEnumValue record; + record._reader = this; + record._handle = handle; + var offset = (uint)handle.Offset; + offset = _streamReader.Read(offset, out record._value); + offset = _streamReader.Read(offset, out record._type); + return record; + } // GetConstantEnumValue + public ConstantHandleArray GetConstantHandleArray(ConstantHandleArrayHandle handle) { ConstantHandleArray record; @@ -10952,11 +10950,6 @@ internal Handle ToHandle(ConstantBooleanValueHandle handle) return new Handle(handle._value); } // ToHandle - internal Handle ToHandle(ConstantBoxedEnumValueHandle handle) - { - return new Handle(handle._value); - } // ToHandle - internal Handle ToHandle(ConstantByteArrayHandle handle) { return new Handle(handle._value); @@ -10992,6 +10985,11 @@ internal Handle ToHandle(ConstantEnumArrayHandle handle) return new Handle(handle._value); } // ToHandle + internal Handle ToHandle(ConstantEnumValueHandle handle) + { + return new Handle(handle._value); + } // ToHandle + internal Handle ToHandle(ConstantHandleArrayHandle handle) { return new Handle(handle._value); @@ -11267,11 +11265,6 @@ internal ConstantBooleanValueHandle ToConstantBooleanValueHandle(Handle handle) return new ConstantBooleanValueHandle(handle._value); } // ToConstantBooleanValueHandle - internal ConstantBoxedEnumValueHandle ToConstantBoxedEnumValueHandle(Handle handle) - { - return new ConstantBoxedEnumValueHandle(handle._value); - } // ToConstantBoxedEnumValueHandle - internal ConstantByteArrayHandle ToConstantByteArrayHandle(Handle handle) { return new ConstantByteArrayHandle(handle._value); @@ -11307,6 +11300,11 @@ internal ConstantEnumArrayHandle ToConstantEnumArrayHandle(Handle handle) return new ConstantEnumArrayHandle(handle._value); } // ToConstantEnumArrayHandle + internal ConstantEnumValueHandle ToConstantEnumValueHandle(Handle handle) + { + return new ConstantEnumValueHandle(handle._value); + } // ToConstantEnumValueHandle + internal ConstantHandleArrayHandle ToConstantHandleArrayHandle(Handle handle) { return new ConstantHandleArrayHandle(handle._value); @@ -11582,11 +11580,6 @@ internal bool IsNull(ConstantBooleanValueHandle handle) return (handle._value & 0x00FFFFFF) == 0; } // IsNull - internal bool IsNull(ConstantBoxedEnumValueHandle handle) - { - return (handle._value & 0x00FFFFFF) == 0; - } // IsNull - internal bool IsNull(ConstantByteArrayHandle handle) { return (handle._value & 0x00FFFFFF) == 0; @@ -11622,6 +11615,11 @@ internal bool IsNull(ConstantEnumArrayHandle handle) return (handle._value & 0x00FFFFFF) == 0; } // IsNull + internal bool IsNull(ConstantEnumValueHandle handle) + { + return (handle._value & 0x00FFFFFF) == 0; + } // IsNull + internal bool IsNull(ConstantHandleArrayHandle handle) { return (handle._value & 0x00FFFFFF) == 0; diff --git a/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.CustomAttribute.cs b/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.CustomAttribute.cs index 60f74b9402bb80..311d19d6f73c27 100644 --- a/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.CustomAttribute.cs +++ b/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.CustomAttribute.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Collections.Immutable; using Internal.Metadata.NativeFormat.Writer; @@ -11,6 +10,7 @@ using Debug = System.Diagnostics.Debug; using NamedArgumentMemberKind = Internal.Metadata.NativeFormat.NamedArgumentMemberKind; +using UnreachableException = System.Diagnostics.UnreachableException; namespace ILCompiler.Metadata { @@ -20,52 +20,60 @@ private List HandleCustomAttributes(Cts.Ecma.EcmaModule module, { List customAttributes = new List(attributes.Count); - var attributeTypeProvider = new Cts.Ecma.CustomAttributeTypeProvider(module); - - Ecma.MetadataReader reader = module.MetadataReader; - foreach (var attributeHandle in attributes) { if (!_policy.GeneratesMetadata(module, attributeHandle)) continue; - Ecma.CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); - // TODO-NICE: We can intern the attributes based on the CA constructor and blob bytes - - Cts.MethodDesc constructor = module.GetMethod(attribute.Constructor); - var decodedValue = attribute.DecodeValue(attributeTypeProvider); - - customAttributes.Add(HandleCustomAttribute(constructor, decodedValue)); + customAttributes.Add(HandleCustomAttribute(module, attributeHandle)); } return customAttributes; } - private CustomAttribute HandleCustomAttribute(Cts.MethodDesc constructor, Ecma.CustomAttributeValue decodedValue) + private CustomAttribute HandleCustomAttribute(Cts.Ecma.EcmaModule module, Ecma.CustomAttributeHandle attributeHandle) { + Ecma.MetadataReader reader = module.MetadataReader; + Ecma.CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); + + Cts.MethodDesc constructor = module.GetMethod(attribute.Constructor); + CustomAttribute result = new CustomAttribute { Constructor = HandleQualifiedMethod(constructor), }; - result.FixedArguments.Capacity = decodedValue.FixedArguments.Length; - foreach (var decodedArgument in decodedValue.FixedArguments) + Ecma.BlobReader valueReader = reader.GetBlobReader(attribute.Value); + + ushort prolog = valueReader.ReadUInt16(); // Version + Debug.Assert(prolog == 1); + + Cts.MethodSignature sig = constructor.Signature; + result.FixedArguments.Capacity = sig.Length; + foreach (Cts.TypeDesc paramType in sig) { - var fixedArgument = HandleCustomAttributeConstantValue(decodedArgument.Type, decodedArgument.Value); + var fixedArgument = paramType.IsArray ? + HandleCustomAttributeConstantArray(module, TypeDescToSerializationTypeCode(((Cts.ArrayType)paramType).ElementType), ref valueReader) : + HandleCustomAttributeConstantValue(module, TypeDescToSerializationTypeCode(paramType), ref valueReader); result.FixedArguments.Add(fixedArgument); } - result.NamedArguments.Capacity = decodedValue.NamedArguments.Length; - foreach (var decodedArgument in decodedValue.NamedArguments) + ushort numNamed = valueReader.ReadUInt16(); + result.NamedArguments.Capacity = numNamed; + for (int i = 0; i < numNamed; i++) { + byte flag = valueReader.ReadByte(); + Cts.TypeDesc type = SerializationTypeToType(module, ref valueReader); var namedArgument = new NamedArgument { - Flags = decodedArgument.Kind == Ecma.CustomAttributeNamedArgumentKind.Field ? + Flags = flag == (byte)Ecma.CustomAttributeNamedArgumentKind.Field ? NamedArgumentMemberKind.Field : NamedArgumentMemberKind.Property, - Name = HandleString(decodedArgument.Name), - Type = HandleType(decodedArgument.Type), - Value = HandleCustomAttributeConstantValue(decodedArgument.Type, decodedArgument.Value) + Type = HandleType(type), + Name = HandleString(valueReader.ReadSerializedString()), + Value = type.IsArray ? + HandleCustomAttributeConstantArray(module, TypeDescToSerializationTypeCode(((Cts.ArrayType)type).ElementType), ref valueReader) : + HandleCustomAttributeConstantValue(module, TypeDescToSerializationTypeCode(type), ref valueReader) }; result.NamedArguments.Add(namedArgument); } @@ -73,142 +81,186 @@ private CustomAttribute HandleCustomAttribute(Cts.MethodDesc constructor, Ecma.C return result; } - private MetadataRecord HandleCustomAttributeConstantValue(Cts.TypeDesc type, object value) + private static Ecma.SerializationTypeCode TypeDescToSerializationTypeCode(Cts.TypeDesc type) { + Debug.Assert((int)Cts.TypeFlags.Boolean == (int)Ecma.SerializationTypeCode.Boolean); + switch (type.UnderlyingType.Category) { - case Cts.TypeFlags.Boolean: - return new ConstantBooleanValue { Value = (bool)value }; - case Cts.TypeFlags.Byte: - return new ConstantByteValue { Value = (byte)value }; - case Cts.TypeFlags.Char: - return new ConstantCharValue { Value = (char)value }; - case Cts.TypeFlags.Double: - return new ConstantDoubleValue { Value = (double)value }; - case Cts.TypeFlags.Int16: - return new ConstantInt16Value { Value = (short)value }; - case Cts.TypeFlags.Int32: - return new ConstantInt32Value { Value = (int)value }; - case Cts.TypeFlags.Int64: - return new ConstantInt64Value { Value = (long)value }; - case Cts.TypeFlags.SByte: - return new ConstantSByteValue { Value = (sbyte)value }; - case Cts.TypeFlags.Single: - return new ConstantSingleValue { Value = (float)value }; - case Cts.TypeFlags.UInt16: - return new ConstantUInt16Value { Value = (ushort)value }; - case Cts.TypeFlags.UInt32: - return new ConstantUInt32Value { Value = (uint)value }; - case Cts.TypeFlags.UInt64: - return new ConstantUInt64Value { Value = (ulong)value }; + case Cts.TypeFlags.Single: return Ecma.SerializationTypeCode.Single; + case Cts.TypeFlags.Double: return Ecma.SerializationTypeCode.Double; + case <= Cts.TypeFlags.UInt64: return (Ecma.SerializationTypeCode)type.UnderlyingType.Category; + default: + if (type.IsObject) + return Ecma.SerializationTypeCode.TaggedObject; + + if (type.IsString) + return Ecma.SerializationTypeCode.String; + + if (type is not Cts.MetadataType { Name: "Type", Namespace: "System" }) + throw new UnreachableException(); + + return Ecma.SerializationTypeCode.Type; } + } + + private static Cts.TypeDesc SerializationTypeToType(Cts.Ecma.EcmaModule module, ref Ecma.BlobReader valueReader) + { + Ecma.SerializationTypeCode typeCode = valueReader.ReadSerializationTypeCode(); - if (value == null) + switch (typeCode) { - return new ConstantReferenceValue(); + case Ecma.SerializationTypeCode.Type: return module.Context.SystemModule.GetType("System", "Type"); + case Ecma.SerializationTypeCode.SZArray: return module.Context.GetArrayType(SerializationTypeToType(module, ref valueReader)); + case Ecma.SerializationTypeCode.Enum: return Cts.CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeName(module, valueReader.ReadSerializedString()); + case Ecma.SerializationTypeCode.String: return module.Context.GetWellKnownType(Cts.WellKnownType.String); + case Ecma.SerializationTypeCode.TaggedObject: return module.Context.GetWellKnownType(Cts.WellKnownType.Object); + case Ecma.SerializationTypeCode.Single: return module.Context.GetWellKnownType(Cts.WellKnownType.Single); + case Ecma.SerializationTypeCode.Double: return module.Context.GetWellKnownType(Cts.WellKnownType.Double); + case <= Ecma.SerializationTypeCode.UInt64: return module.Context.GetWellKnownType((Cts.WellKnownType)typeCode); } - if (type.IsString) + Cts.ThrowHelper.ThrowBadImageFormatException(); + return null; // unreached + } + + private MetadataRecord HandleCustomAttributeConstantValue(Cts.Ecma.EcmaModule module, Ecma.SerializationTypeCode typeCode, ref Ecma.BlobReader valueReader) + { + if (typeCode == Ecma.SerializationTypeCode.TaggedObject) { - return HandleString((string)value); + typeCode = valueReader.ReadSerializationTypeCode(); } - if (type.IsSzArray) + if (typeCode == Ecma.SerializationTypeCode.Enum) { - return HandleCustomAttributeConstantArray( - (Cts.ArrayType)type, - (ImmutableArray>)value); + Cts.TypeDesc enumType = Cts.CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeName(module, valueReader.ReadSerializedString()); + return new ConstantEnumValue + { + Value = HandleCustomAttributeConstantValue(module, TypeDescToSerializationTypeCode(enumType), ref valueReader), + Type = HandleType(enumType) + }; } - Debug.Assert(value is Cts.TypeDesc); - Debug.Assert(type is Cts.MetadataType - && ((Cts.MetadataType)type).Name == "Type" - && ((Cts.MetadataType)type).Namespace == "System"); + if (typeCode == Ecma.SerializationTypeCode.String) + { + string s = valueReader.ReadSerializedString(); + return s == null ? new ConstantReferenceValue() : HandleString(s); + } + + if (typeCode == Ecma.SerializationTypeCode.Type) + { + string s = valueReader.ReadSerializedString(); + return s == null ? new ConstantReferenceValue() : HandleType(Cts.CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeName(module, s)); + } - return HandleType((Cts.TypeDesc)value); + return typeCode switch + { + Ecma.SerializationTypeCode.Boolean => new ConstantBooleanValue { Value = valueReader.ReadBoolean() }, + Ecma.SerializationTypeCode.Char => new ConstantCharValue { Value = valueReader.ReadChar() }, + Ecma.SerializationTypeCode.Byte => new ConstantByteValue { Value = valueReader.ReadByte() }, + Ecma.SerializationTypeCode.SByte => new ConstantSByteValue { Value = valueReader.ReadSByte() }, + Ecma.SerializationTypeCode.Int16 => new ConstantInt16Value { Value = valueReader.ReadInt16() }, + Ecma.SerializationTypeCode.UInt16 => new ConstantUInt16Value { Value = valueReader.ReadUInt16() }, + Ecma.SerializationTypeCode.Int32 => new ConstantInt32Value { Value = valueReader.ReadInt32() }, + Ecma.SerializationTypeCode.UInt32 => new ConstantUInt32Value { Value = valueReader.ReadUInt32() }, + Ecma.SerializationTypeCode.Int64 => new ConstantInt64Value { Value = valueReader.ReadInt64() }, + Ecma.SerializationTypeCode.UInt64 => new ConstantUInt64Value { Value = valueReader.ReadUInt64() }, + Ecma.SerializationTypeCode.Single => new ConstantSingleValue { Value = valueReader.ReadSingle() }, + Ecma.SerializationTypeCode.Double => new ConstantDoubleValue { Value = valueReader.ReadDouble() }, + Ecma.SerializationTypeCode.SZArray => HandleCustomAttributeConstantArray(module, valueReader.ReadSerializationTypeCode(), ref valueReader), + _ => throw new UnreachableException() + }; } - private MetadataRecord HandleCustomAttributeConstantArray( - Cts.ArrayType type, ImmutableArray> value) + private MetadataRecord HandleCustomAttributeConstantArray(Cts.Ecma.EcmaModule module, Ecma.SerializationTypeCode elementTypeCode, ref Ecma.BlobReader valueReader) { - Cts.TypeDesc elementType = type.ElementType; - - if (elementType.IsEnum) + if (elementTypeCode == Ecma.SerializationTypeCode.Enum) { - Cts.TypeSystemContext context = type.Context; + Cts.TypeDesc enumType = Cts.CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeName(module, valueReader.ReadSerializedString()); return new ConstantEnumArray { - ElementType = HandleType(elementType), - Value = HandleCustomAttributeConstantArray(context.GetArrayType(elementType.UnderlyingType), value), + ElementType = HandleType(enumType), + Value = HandleCustomAttributeConstantArray(module, TypeDescToSerializationTypeCode(enumType), ref valueReader), }; } - switch (elementType.Category) - { - case Cts.TypeFlags.Boolean: - return new ConstantBooleanArray { Value = GetCustomAttributeConstantArrayElements(value) }; - case Cts.TypeFlags.Byte: - return new ConstantByteArray { Value = GetCustomAttributeConstantArrayElements(value) }; - case Cts.TypeFlags.Char: - return new ConstantCharArray { Value = GetCustomAttributeConstantArrayElements(value) }; - case Cts.TypeFlags.Double: - return new ConstantDoubleArray { Value = GetCustomAttributeConstantArrayElements(value) }; - case Cts.TypeFlags.Int16: - return new ConstantInt16Array { Value = GetCustomAttributeConstantArrayElements(value) }; - case Cts.TypeFlags.Int32: - return new ConstantInt32Array { Value = GetCustomAttributeConstantArrayElements(value) }; - case Cts.TypeFlags.Int64: - return new ConstantInt64Array { Value = GetCustomAttributeConstantArrayElements(value) }; - case Cts.TypeFlags.SByte: - return new ConstantSByteArray { Value = GetCustomAttributeConstantArrayElements(value) }; - case Cts.TypeFlags.Single: - return new ConstantSingleArray { Value = GetCustomAttributeConstantArrayElements(value) }; - case Cts.TypeFlags.UInt16: - return new ConstantUInt16Array { Value = GetCustomAttributeConstantArrayElements(value) }; - case Cts.TypeFlags.UInt32: - return new ConstantUInt32Array { Value = GetCustomAttributeConstantArrayElements(value) }; - case Cts.TypeFlags.UInt64: - return new ConstantUInt64Array { Value = GetCustomAttributeConstantArrayElements(value) }; + int count = valueReader.ReadInt32(); + if (count == -1) + { + return new ConstantReferenceValue(); } - if (elementType.IsString) + if (elementTypeCode is Ecma.SerializationTypeCode.String) { - var record = new ConstantStringArray(); - record.Value.Capacity = value.Length; - foreach (var element in value) + var handleArray = new ConstantStringArray(); + handleArray.Value.Capacity = count; + for (int i = 0; i < count; i++) { - MetadataRecord elementRecord = element.Value == null ? - (MetadataRecord)new ConstantReferenceValue() : HandleString((string)element.Value); - record.Value.Add(elementRecord); + string val = valueReader.ReadSerializedString(); + handleArray.Value.Add(val == null ? new ConstantReferenceValue() : HandleString(val)); } - return record; + return handleArray; } - var result = new ConstantHandleArray(); - result.Value.Capacity = value.Length; - for (int i = 0; i < value.Length; i++) + if (elementTypeCode is Ecma.SerializationTypeCode.TaggedObject or Ecma.SerializationTypeCode.Type) { - MetadataRecord elementRecord = HandleCustomAttributeConstantValue(value[i].Type, value[i].Value); - if (value[i].Type.IsEnum) + var handleArray = new ConstantHandleArray(); + handleArray.Value.Capacity = count; + for (int i = 0; i < count; i++) { - elementRecord = new ConstantBoxedEnumValue - { - Value = elementRecord, - Type = HandleType(value[i].Type) - }; + Ecma.SerializationTypeCode typecode = elementTypeCode == Ecma.SerializationTypeCode.Type ? Ecma.SerializationTypeCode.Type : valueReader.ReadSerializationTypeCode(); + handleArray.Value.Add(HandleCustomAttributeConstantValue(module, typecode, ref valueReader)); } - result.Value.Add(elementRecord); + return handleArray; } - return result; + return elementTypeCode switch + { + Ecma.SerializationTypeCode.Boolean => new ConstantBooleanArray { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + Ecma.SerializationTypeCode.Char => new ConstantCharArray { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + Ecma.SerializationTypeCode.SByte => new ConstantSByteArray { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + Ecma.SerializationTypeCode.Byte => new ConstantByteArray { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + Ecma.SerializationTypeCode.Int16 => new ConstantInt16Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + Ecma.SerializationTypeCode.UInt16 => new ConstantUInt16Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + Ecma.SerializationTypeCode.Int32 => new ConstantInt32Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + Ecma.SerializationTypeCode.UInt32 => new ConstantUInt32Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + Ecma.SerializationTypeCode.Int64 => new ConstantInt64Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + Ecma.SerializationTypeCode.UInt64 => new ConstantUInt64Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + Ecma.SerializationTypeCode.Single => new ConstantSingleArray { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + Ecma.SerializationTypeCode.Double => new ConstantDoubleArray { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) }, + _ => throw new UnreachableException() + }; } - private static TValue[] GetCustomAttributeConstantArrayElements(ImmutableArray> value) + private static TValue[] GetCustomAttributeConstantArrayElements(ref Ecma.BlobReader blobReader, int count) { - TValue[] result = new TValue[value.Length]; - for (int i = 0; i < value.Length; i++) + TValue[] result = new TValue[count]; + for (int i = 0; i < count; i++) { - result[i] = (TValue)value[i].Value; + if (typeof(TValue) == typeof(bool)) + result[i] = (TValue)(object)blobReader.ReadBoolean(); + if (typeof(TValue) == typeof(char)) + result[i] = (TValue)(object)blobReader.ReadChar(); + if (typeof(TValue) == typeof(sbyte)) + result[i] = (TValue)(object)blobReader.ReadSByte(); + if (typeof(TValue) == typeof(byte)) + result[i] = (TValue)(object)blobReader.ReadByte(); + if (typeof(TValue) == typeof(short)) + result[i] = (TValue)(object)blobReader.ReadInt16(); + if (typeof(TValue) == typeof(ushort)) + result[i] = (TValue)(object)blobReader.ReadUInt16(); + if (typeof(TValue) == typeof(int)) + result[i] = (TValue)(object)blobReader.ReadInt32(); + if (typeof(TValue) == typeof(uint)) + result[i] = (TValue)(object)blobReader.ReadUInt32(); + if (typeof(TValue) == typeof(long)) + result[i] = (TValue)(object)blobReader.ReadInt64(); + if (typeof(TValue) == typeof(ulong)) + result[i] = (TValue)(object)blobReader.ReadUInt64(); + if (typeof(TValue) == typeof(float)) + result[i] = (TValue)(object)blobReader.ReadSingle(); + if (typeof(TValue) == typeof(double)) + result[i] = (TValue)(object)blobReader.ReadDouble(); } return result; } diff --git a/src/coreclr/tools/aot/ILCompiler.MetadataTransform/Internal/Metadata/NativeFormat/Writer/MdBinaryWriterGen.cs b/src/coreclr/tools/aot/ILCompiler.MetadataTransform/Internal/Metadata/NativeFormat/Writer/MdBinaryWriterGen.cs index 74c013f1a99cb2..65173a6e7f6ddd 100644 --- a/src/coreclr/tools/aot/ILCompiler.MetadataTransform/Internal/Metadata/NativeFormat/Writer/MdBinaryWriterGen.cs +++ b/src/coreclr/tools/aot/ILCompiler.MetadataTransform/Internal/Metadata/NativeFormat/Writer/MdBinaryWriterGen.cs @@ -367,28 +367,6 @@ public static void Write(this NativeWriter writer, List va } } // Write - public static void Write(this NativeWriter writer, ConstantBoxedEnumValue record) - { - if (record != null) - writer.WriteUnsigned((uint)record.Handle.Offset); - else - writer.WriteUnsigned(0); - } // Write - - public static void Write(this NativeWriter writer, List values) - { - if (values == null) - { - writer.WriteUnsigned(0); - return; - } - writer.WriteUnsigned((uint)values.Count); - foreach (ConstantBoxedEnumValue value in values) - { - writer.Write(value); - } - } // Write - public static void Write(this NativeWriter writer, ConstantByteArray record) { if (record != null) @@ -543,6 +521,28 @@ public static void Write(this NativeWriter writer, List value } } // Write + public static void Write(this NativeWriter writer, ConstantEnumValue record) + { + if (record != null) + writer.WriteUnsigned((uint)record.Handle.Offset); + else + writer.WriteUnsigned(0); + } // Write + + public static void Write(this NativeWriter writer, List values) + { + if (values == null) + { + writer.WriteUnsigned(0); + return; + } + writer.WriteUnsigned((uint)values.Count); + foreach (ConstantEnumValue value in values) + { + writer.Write(value); + } + } // Write + public static void Write(this NativeWriter writer, ConstantHandleArray record) { if (record != null) diff --git a/src/coreclr/tools/aot/ILCompiler.MetadataTransform/Internal/Metadata/NativeFormat/Writer/NativeFormatWriterGen.cs b/src/coreclr/tools/aot/ILCompiler.MetadataTransform/Internal/Metadata/NativeFormat/Writer/NativeFormatWriterGen.cs index 3ea8d18d6a5cfd..50750233913581 100644 --- a/src/coreclr/tools/aot/ILCompiler.MetadataTransform/Internal/Metadata/NativeFormat/Writer/NativeFormatWriterGen.cs +++ b/src/coreclr/tools/aot/ILCompiler.MetadataTransform/Internal/Metadata/NativeFormat/Writer/NativeFormatWriterGen.cs @@ -303,88 +303,6 @@ internal static ConstantBooleanValueHandle AsHandle(ConstantBooleanValue record) public bool Value; } // ConstantBooleanValue - public partial class ConstantBoxedEnumValue : MetadataRecord - { - public override HandleType HandleType - { - get - { - return HandleType.ConstantBoxedEnumValue; - } - } // HandleType - - internal override void Visit(IRecordVisitor visitor) - { - Value = visitor.Visit(this, Value); - Type = visitor.Visit(this, Type); - } // Visit - - public override sealed bool Equals(Object obj) - { - if (Object.ReferenceEquals(this, obj)) return true; - var other = obj as ConstantBoxedEnumValue; - if (other == null) return false; - if (!Object.Equals(Value, other.Value)) return false; - if (!Object.Equals(Type, other.Type)) return false; - return true; - } // Equals - - public override sealed int GetHashCode() - { - if (_hash != 0) - return _hash; - EnterGetHashCode(); - int hash = 879057725; - hash = ((hash << 13) - (hash >> 19)) ^ (Value == null ? 0 : Value.GetHashCode()); - hash = ((hash << 13) - (hash >> 19)) ^ (Type == null ? 0 : Type.GetHashCode()); - LeaveGetHashCode(); - _hash = hash; - return _hash; - } // GetHashCode - - internal override void Save(NativeWriter writer) - { - Debug.Assert(Value == null || - Value.HandleType == HandleType.ConstantByteValue || - Value.HandleType == HandleType.ConstantSByteValue || - Value.HandleType == HandleType.ConstantInt16Value || - Value.HandleType == HandleType.ConstantUInt16Value || - Value.HandleType == HandleType.ConstantInt32Value || - Value.HandleType == HandleType.ConstantUInt32Value || - Value.HandleType == HandleType.ConstantInt64Value || - Value.HandleType == HandleType.ConstantUInt64Value); - writer.Write(Value); - Debug.Assert(Type == null || - Type.HandleType == HandleType.TypeDefinition || - Type.HandleType == HandleType.TypeReference || - Type.HandleType == HandleType.TypeSpecification); - writer.Write(Type); - } // Save - - internal static ConstantBoxedEnumValueHandle AsHandle(ConstantBoxedEnumValue record) - { - if (record == null) - { - return new ConstantBoxedEnumValueHandle(0); - } - else - { - return record.Handle; - } - } // AsHandle - - internal new ConstantBoxedEnumValueHandle Handle - { - get - { - return new ConstantBoxedEnumValueHandle(HandleOffset); - } - } // Handle - - public MetadataRecord Value; - public MetadataRecord Type; - } // ConstantBoxedEnumValue - public partial class ConstantByteArray : MetadataRecord { public override HandleType HandleType @@ -841,6 +759,75 @@ internal static ConstantEnumArrayHandle AsHandle(ConstantEnumArray record) public MetadataRecord Value; } // ConstantEnumArray + public partial class ConstantEnumValue : MetadataRecord + { + public override HandleType HandleType + { + get + { + return HandleType.ConstantEnumValue; + } + } // HandleType + + internal override void Visit(IRecordVisitor visitor) + { + Value = visitor.Visit(this, Value); + Type = visitor.Visit(this, Type); + } // Visit + + public override sealed bool Equals(Object obj) + { + if (Object.ReferenceEquals(this, obj)) return true; + var other = obj as ConstantEnumValue; + if (other == null) return false; + if (!Object.Equals(Value, other.Value)) return false; + if (!Object.Equals(Type, other.Type)) return false; + return true; + } // Equals + + public override sealed int GetHashCode() + { + if (_hash != 0) + return _hash; + EnterGetHashCode(); + int hash = 1536570168; + hash = ((hash << 13) - (hash >> 19)) ^ (Value == null ? 0 : Value.GetHashCode()); + hash = ((hash << 13) - (hash >> 19)) ^ (Type == null ? 0 : Type.GetHashCode()); + LeaveGetHashCode(); + _hash = hash; + return _hash; + } // GetHashCode + + internal override void Save(NativeWriter writer) + { + writer.Write(Value); + writer.Write(Type); + } // Save + + internal static ConstantEnumValueHandle AsHandle(ConstantEnumValue record) + { + if (record == null) + { + return new ConstantEnumValueHandle(0); + } + else + { + return record.Handle; + } + } // AsHandle + + internal new ConstantEnumValueHandle Handle + { + get + { + return new ConstantEnumValueHandle(HandleOffset); + } + } // Handle + + public MetadataRecord Value; + public MetadataRecord Type; + } // ConstantEnumValue + public partial class ConstantHandleArray : MetadataRecord { public override HandleType HandleType @@ -2214,6 +2201,7 @@ internal override void Save(NativeWriter writer) handle.HandleType == HandleType.ConstantDoubleArray || handle.HandleType == HandleType.ConstantDoubleValue || handle.HandleType == HandleType.ConstantEnumArray || + handle.HandleType == HandleType.ConstantEnumValue || handle.HandleType == HandleType.ConstantHandleArray || handle.HandleType == HandleType.ConstantInt16Array || handle.HandleType == HandleType.ConstantInt16Value || @@ -2426,6 +2414,7 @@ internal override void Save(NativeWriter writer) DefaultValue.HandleType == HandleType.ConstantDoubleArray || DefaultValue.HandleType == HandleType.ConstantDoubleValue || DefaultValue.HandleType == HandleType.ConstantEnumArray || + DefaultValue.HandleType == HandleType.ConstantEnumValue || DefaultValue.HandleType == HandleType.ConstantHandleArray || DefaultValue.HandleType == HandleType.ConstantInt16Array || DefaultValue.HandleType == HandleType.ConstantInt16Value || @@ -3341,6 +3330,7 @@ internal override void Save(NativeWriter writer) Value.HandleType == HandleType.ConstantDoubleArray || Value.HandleType == HandleType.ConstantDoubleValue || Value.HandleType == HandleType.ConstantEnumArray || + Value.HandleType == HandleType.ConstantEnumValue || Value.HandleType == HandleType.ConstantHandleArray || Value.HandleType == HandleType.ConstantInt16Array || Value.HandleType == HandleType.ConstantInt16Value || @@ -3606,6 +3596,7 @@ internal override void Save(NativeWriter writer) DefaultValue.HandleType == HandleType.ConstantDoubleArray || DefaultValue.HandleType == HandleType.ConstantDoubleValue || DefaultValue.HandleType == HandleType.ConstantEnumArray || + DefaultValue.HandleType == HandleType.ConstantEnumValue || DefaultValue.HandleType == HandleType.ConstantHandleArray || DefaultValue.HandleType == HandleType.ConstantInt16Array || DefaultValue.HandleType == HandleType.ConstantInt16Value || @@ -3801,6 +3792,7 @@ internal override void Save(NativeWriter writer) DefaultValue.HandleType == HandleType.ConstantDoubleArray || DefaultValue.HandleType == HandleType.ConstantDoubleValue || DefaultValue.HandleType == HandleType.ConstantEnumArray || + DefaultValue.HandleType == HandleType.ConstantEnumValue || DefaultValue.HandleType == HandleType.ConstantHandleArray || DefaultValue.HandleType == HandleType.ConstantInt16Array || DefaultValue.HandleType == HandleType.ConstantInt16Value || diff --git a/src/libraries/System.Runtime/tests/System.Reflection.Tests/CustomAttributeTests.cs b/src/libraries/System.Runtime/tests/System.Reflection.Tests/CustomAttributeTests.cs index ce6e5ecddf5602..c3c7f3c465e413 100644 --- a/src/libraries/System.Runtime/tests/System.Reflection.Tests/CustomAttributeTests.cs +++ b/src/libraries/System.Runtime/tests/System.Reflection.Tests/CustomAttributeTests.cs @@ -237,5 +237,43 @@ public void CustomAttributeProvider () Assert.Equal(typeof(MyParameterAttribute), customAttributesData[0].AttributeType); Assert.Equal(typeof(MyPropertyAttribute), customAttributesData[1].AttributeType); } + + internal enum EnumForArrays { Zero, One, Two } + + [CustomAttributeWithObjects(EnumForArrays.One, new object[] { EnumForArrays.One }, new EnumForArrays[] { EnumForArrays.Two }, + B1 = EnumForArrays.One, B2 = new object[] { EnumForArrays.One }, B3 = new EnumForArrays[] { EnumForArrays.Two })] + internal class ClassWithObjectEnums { } + + internal class CustomAttributeWithObjectsAttribute(object a1, object a2, object a3) : Attribute + { + public object A1 => a1; + public object A2 => a2; + public object A3 => a3; + + public object B1 { get; set; } + public object B2 { get; set; } + public object B3 { get; set; } + } + + [Fact] + public void BoxedEnumAttributes() + { + CustomAttributeWithObjectsAttribute att = typeof(ClassWithObjectEnums) + .GetCustomAttribute()!; + + Assert.Equal(typeof(EnumForArrays), att.A1.GetType()); + Assert.Equal(typeof(object[]), att.A2.GetType()); + Assert.Equal(typeof(EnumForArrays), ((object[])att.A2)[0].GetType()); + Assert.Equal(EnumForArrays.One, ((object[])att.A2)[0]); + Assert.Equal(typeof(EnumForArrays[]), att.A3.GetType()); + Assert.Equal(EnumForArrays.Two, ((EnumForArrays[])att.A3)[0]); + + Assert.Equal(typeof(EnumForArrays), att.B1.GetType()); + Assert.Equal(typeof(object[]), att.B2.GetType()); + Assert.Equal(typeof(EnumForArrays), ((object[])att.B2)[0].GetType()); + Assert.Equal(EnumForArrays.One, ((object[])att.B2)[0]); + Assert.Equal(typeof(EnumForArrays[]), att.B3.GetType()); + Assert.Equal(EnumForArrays.Two, ((EnumForArrays[])att.B3)[0]); + } } }