diff options
author | Anton Lapounov <antonl@microsoft.com> | 2017-06-16 22:02:07 +0300 |
---|---|---|
committer | Anton Lapounov <antonl@microsoft.com> | 2017-06-16 22:02:07 +0300 |
commit | 9b5108849025b1d1ea5f780c8bfefbf1783eee36 (patch) | |
tree | 7489aa0563d74a968f0f5a5bacd52dbc91e12aec | |
parent | 98c8b4a802146172aa1955467c2fbe6bb3760b69 (diff) |
Distinguish positive and negative zeros in metadata writer.
Bug: https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems/edit/442050
CR: JKotas
[tfs-changeset: 1661975]
4 files changed, 63 insertions, 43 deletions
diff --git a/src/Common/src/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs b/src/Common/src/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs index 54d049aa6..d5da54db8 100644 --- a/src/Common/src/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs +++ b/src/Common/src/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs @@ -26,25 +26,23 @@ public enum RecordDefFlags [Flags] public enum MemberDefFlags { - Map = 0x0001, // => Dictionary<string, RecordType> for MetadataWriter - // => List<RecordType> for MetadataReader - List = 0x0002, // => List<RecordType> - Array = 0x0004, // => RecordType[] + Map = 0x0001, // => List<RecordType> for writer + List = 0x0002, // => List<RecordType> for writer + Array = 0x0004, // => RecordType[] for writer Collection = MemberDefFlags.Map | MemberDefFlags.List | MemberDefFlags.Array, Sequence = MemberDefFlags.List | MemberDefFlags.Array, - RecordRef = 0x0008, // => RecordTypeHandle - - Ref = MemberDefFlags.RecordRef, + RecordRef = 0x0008, Child = 0x0010, // Member instance is logically defined and owned by record; // otherwise instance may be shared (such as a TypeRef). - Name = 0x0020, // May be used as the member"s simple name for diagnostics. + Name = 0x0020, // May be used as the member's simple name for diagnostics. NotPersisted = 0x0040, // Indicates member is not written to or read from metadata. Compare = 0x0080, // Indicates member should be used for equality functionality. EnumerateForHashCode = 0x0100, // Indicates that the collection is safe to be enumerated in GetHashCode // without causing reentrancy + CustomCompare = 0x0200, // Indicates that this member uses a custom comparer } public enum MemberTypeKind @@ -86,14 +84,14 @@ public class MemberDef else { typeName = (kind == MemberTypeKind.WriterField) ? - (TypeName != null ? (string)TypeName : "MetadataRecord"): $"{ TypeName}Handle"; + (TypeName != null ? (string)TypeName : "MetadataRecord"): $"{TypeName}Handle"; } } else { typeName = (string)TypeName; } - if ((Flags & (MemberDefFlags.Array | MemberDefFlags.List | MemberDefFlags.Map)) != 0) + if ((Flags & MemberDefFlags.Collection) != 0) { if (kind == MemberTypeKind.WriterField) { @@ -119,10 +117,7 @@ public class MemberDef if (typeSet == null) return null; - string result = "One of: " + typeSet[0]; - for (int i = 1; i < typeSet.Length; i++) - result += ", " + typeSet[i]; - return result; + return "One of: " + String.Join(", ", typeSet); } } @@ -161,14 +156,16 @@ public class EnumType public class PrimitiveType { - public PrimitiveType(string name, string typeName) + public PrimitiveType(string name, string typeName, bool customCompare = false) { Name = name; TypeName = typeName; + CustomCompare = customCompare; } readonly public string Name; readonly public string TypeName; + readonly public bool CustomCompare; } /// <summary> @@ -208,8 +205,8 @@ class SchemaDef new PrimitiveType("uint", "UInt32"), new PrimitiveType("long", "Int64"), new PrimitiveType("ulong", "UInt64"), - new PrimitiveType("float", "Single"), - new PrimitiveType("double", "Double"), + new PrimitiveType("float", "Single", customCompare: true), + new PrimitiveType("double", "Double", customCompare: true), }; // These enums supplement those defined by System.Reflection.Primitives. @@ -292,7 +289,8 @@ class SchemaDef new RecordDef( name: "Constant" + primitiveType.TypeName + "Value", members: new MemberDef[] { - new MemberDef(name: "Value", typeName: primitiveType.Name) + new MemberDef(name: "Value", typeName: primitiveType.Name, + flags: primitiveType.CustomCompare ? MemberDefFlags.CustomCompare : 0) } ) ) @@ -326,7 +324,8 @@ class SchemaDef new RecordDef( name: "Constant" + primitiveType.TypeName + "Array", members: new MemberDef[] { - new MemberDef(name: "Value", flags: MemberDefFlags.Array, typeName: primitiveType.TypeName) + new MemberDef(name: "Value", typeName: primitiveType.TypeName, + flags: MemberDefFlags.Array | (primitiveType.CustomCompare ? MemberDefFlags.CustomCompare : 0)) } ) ) @@ -782,9 +781,7 @@ class SchemaDef from member in r.Members let memberTypeName = member.TypeName as string where memberTypeName != null && - ((member.Flags & MemberDefFlags.Array) != 0 || - (member.Flags & MemberDefFlags.List) != 0 || - (member.Flags & MemberDefFlags.Map) != 0) && + (member.Flags & MemberDefFlags.Collection) != 0 && !PrimitiveTypes.Any(pt => pt.TypeName == memberTypeName) select memberTypeName ).Concat(new[] { "ScopeDefinition" }).Distinct().ToArray(); diff --git a/src/Common/src/Internal/Metadata/NativeFormat/Generator/WriterGen.cs b/src/Common/src/Internal/Metadata/NativeFormat/Generator/WriterGen.cs index 25f18c15e..fe1daca06 100644 --- a/src/Common/src/Internal/Metadata/NativeFormat/Generator/WriterGen.cs +++ b/src/Common/src/Internal/Metadata/NativeFormat/Generator/WriterGen.cs @@ -61,14 +61,7 @@ class WriterGen : CsWriter if ((member.Flags & MemberDefFlags.RecordRef) == 0) continue; - if ((member.Flags & (MemberDefFlags.Map | MemberDefFlags.Sequence)) != 0) - { - WriteLine($"{member.Name} = visitor.Visit(this, {member.Name});"); - } - else - { - WriteLine($"{member.Name} = visitor.Visit(this, {member.Name});"); - } + WriteLine($"{member.Name} = visitor.Visit(this, {member.Name});"); } CloseScope("Visit"); @@ -94,17 +87,20 @@ class WriterGen : CsWriter if ((member.Flags & MemberDefFlags.Sequence) != 0) { - WriteLine($"if (!{member.Name}.SequenceEqual(other.{member.Name})) return false;"); + if ((member.Flags & MemberDefFlags.CustomCompare) != 0) + WriteLine($"if (!{member.Name}.SequenceEqual(other.{member.Name}, {member.TypeName}Comparer.Instance)) return false;"); + else + WriteLine($"if (!{member.Name}.SequenceEqual(other.{member.Name})) return false;"); } else - if ((member.Flags & (MemberDefFlags.List | MemberDefFlags.Map)) != 0) + if ((member.Flags & (MemberDefFlags.Map | MemberDefFlags.RecordRef)) != 0) { WriteLine($"if (!Object.Equals({member.Name}, other.{member.Name})) return false;"); } else - if ((member.Flags & MemberDefFlags.RecordRef) != 0) + if ((member.Flags & MemberDefFlags.CustomCompare) != 0) { - WriteLine($"if (!Object.Equals({member.Name}, other.{member.Name})) return false;"); + WriteLine($"if (!CustomComparer.Equals({member.Name}, other.{member.Name})) return false;"); } else { diff --git a/src/ILCompiler.MetadataWriter/src/Internal/Metadata/NativeFormat/Writer/NativeFormatWriterGen.cs b/src/ILCompiler.MetadataWriter/src/Internal/Metadata/NativeFormat/Writer/NativeFormatWriterGen.cs index eee6cd3ea..d503e858e 100644 --- a/src/ILCompiler.MetadataWriter/src/Internal/Metadata/NativeFormat/Writer/NativeFormatWriterGen.cs +++ b/src/ILCompiler.MetadataWriter/src/Internal/Metadata/NativeFormat/Writer/NativeFormatWriterGen.cs @@ -676,7 +676,7 @@ namespace Internal.Metadata.NativeFormat.Writer if (Object.ReferenceEquals(this, obj)) return true; var other = obj as ConstantDoubleArray; if (other == null) return false; - if (!Value.SequenceEqual(other.Value)) return false; + if (!Value.SequenceEqual(other.Value, DoubleComparer.Instance)) return false; return true; } // Equals @@ -745,7 +745,7 @@ namespace Internal.Metadata.NativeFormat.Writer if (Object.ReferenceEquals(this, obj)) return true; var other = obj as ConstantDoubleValue; if (other == null) return false; - if (Value != other.Value) return false; + if (!CustomComparer.Equals(Value, other.Value)) return false; return true; } // Equals @@ -1527,7 +1527,7 @@ namespace Internal.Metadata.NativeFormat.Writer if (Object.ReferenceEquals(this, obj)) return true; var other = obj as ConstantSingleArray; if (other == null) return false; - if (!Value.SequenceEqual(other.Value)) return false; + if (!Value.SequenceEqual(other.Value, SingleComparer.Instance)) return false; return true; } // Equals @@ -1596,7 +1596,7 @@ namespace Internal.Metadata.NativeFormat.Writer if (Object.ReferenceEquals(this, obj)) return true; var other = obj as ConstantSingleValue; if (other == null) return false; - if (Value != other.Value) return false; + if (!CustomComparer.Equals(Value, other.Value)) return false; return true; } // Equals diff --git a/src/ILCompiler.MetadataWriter/src/Internal/Metadata/NativeFormat/Writer/NativeMetadataWriter.cs b/src/ILCompiler.MetadataWriter/src/Internal/Metadata/NativeFormat/Writer/NativeMetadataWriter.cs index 0dec3aad3..5f486ab6d 100644 --- a/src/ILCompiler.MetadataWriter/src/Internal/Metadata/NativeFormat/Writer/NativeMetadataWriter.cs +++ b/src/ILCompiler.MetadataWriter/src/Internal/Metadata/NativeFormat/Writer/NativeMetadataWriter.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#pragma warning disable 649 - using System; using System.IO; using System.Collections.Generic; @@ -567,7 +565,7 @@ namespace Internal.Metadata.NativeFormat.Writer /// </summary> public partial class ConstantStringValue { - public static explicit operator string (ConstantStringValue value) + public static explicit operator string(ConstantStringValue value) { if (value == null) return null; @@ -929,7 +927,7 @@ namespace Internal.Metadata.NativeFormat.Writer ReturnType.ToString(false), name + (GenericParameterCount == 0 ? "" : "`" + GenericParameterCount.ToString()) - + "(" + String.Join(", ", Parameters.Select(p => p.ToString(false))) + + + "(" + String.Join(", ", Parameters.Select(p => p.ToString(false))) + String.Join(", ", VarArgParameters.Select(p => p.ToString(false))) + ")"}.Where(e => !String.IsNullOrWhiteSpace(e))); } } @@ -1120,5 +1118,34 @@ namespace Internal.Metadata.NativeFormat.Writer return true; } } -} + // Distinguishes positive and negative zeros for float and double values + public static class CustomComparer + { + public static unsafe bool Equals(float x, float y) + { + return *(int*)&x == *(int*)&y; + } + + public static bool Equals(double x, double y) + { + return BitConverter.DoubleToInt64Bits(x) == BitConverter.DoubleToInt64Bits(y); + } + } + + public sealed class SingleComparer : IEqualityComparer<float> + { + public static readonly SingleComparer Instance = new SingleComparer(); + + public bool Equals(float x, float y) => CustomComparer.Equals(x, y); + public int GetHashCode(float obj) => obj.GetHashCode(); + } + + public sealed class DoubleComparer : IEqualityComparer<double> + { + public static readonly DoubleComparer Instance = new DoubleComparer(); + + public bool Equals(double x, double y) => CustomComparer.Equals(x, y); + public int GetHashCode(double obj) => obj.GetHashCode(); + } +} |