From 9587beb863448a6c4fc8509a1634c9f747f3be48 Mon Sep 17 00:00:00 2001 From: Atsushi Kanamori Date: Thu, 8 Jun 2017 09:49:27 -0700 Subject: [PATCH 1/3] Use VS autorename to rename the "hi/med/lo/flags" to "uhi/umed/ulo/uflags" --- .../src/System/Decimal.DecCalc.cs | 112 +++++++++--------- .../src/System/Decimal.cs | 102 ++++++++-------- 2 files changed, 107 insertions(+), 107 deletions(-) diff --git a/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs b/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs index e2267de5e0b..09f51be9694 100644 --- a/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs +++ b/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs @@ -15,38 +15,38 @@ public partial struct Decimal // Low level accessors used by a DecCalc and formatting internal uint High { - get { return hi; } - set { hi = value; } + get { return uhi; } + set { uhi = value; } } internal uint Low { - get { return lo; } - set { lo = value; } + get { return ulo; } + set { ulo = value; } } internal uint Mid { - get { return mid; } - set { mid = value; } + get { return umid; } + set { umid = value; } } internal bool Sign { - get { return (flags & SignMask) != 0; } - set { flags = (flags & ~SignMask) | (value ? SignMask : 0); } + get { return (uflags & SignMask) != 0; } + set { uflags = (uflags & ~SignMask) | (value ? SignMask : 0); } } internal int Scale { - get { return (int)((flags & ScaleMask) >> ScaleShift); } - set { flags = (flags & ~ScaleMask) | ((uint)value << ScaleShift); } + get { return (int)((uflags & ScaleMask) >> ScaleShift); } + set { uflags = (uflags & ~ScaleMask) | ((uint)value << ScaleShift); } } private ulong Low64 { - get { return ((ulong)mid << 32) | lo; } - set { mid = (uint)(value >> 32); lo = (uint)value; } + get { return ((ulong)umid << 32) | ulo; } + set { umid = (uint)(value >> 32); ulo = (uint)value; } } #region APIs need by number formatting. @@ -1190,7 +1190,7 @@ private static void RoundUp(uint[] rgulQuo, ref int iScale) // private static Decimal Abs(Decimal d) { - return new Decimal((int)d.lo, (int)d.mid, (int)d.hi, (int)(d.flags & ~SignMask)); + return new Decimal((int)d.ulo, (int)d.umid, (int)d.uhi, (int)(d.uflags & ~SignMask)); } /*** @@ -1219,9 +1219,9 @@ private static uint DecFixInt(ref Decimal input, ref Decimal result) if (input.Scale > 0) { - tmpNum[0] = input.lo; - tmpNum[1] = input.mid; - tmpNum[2] = input.hi; + tmpNum[0] = input.ulo; + tmpNum[1] = input.umid; + tmpNum[2] = input.uhi; scale = input.Scale; result.Sign = input.Sign; remainder = 0; @@ -1237,9 +1237,9 @@ private static uint DecFixInt(ref Decimal input, ref Decimal result) scale -= MaxInt32Scale; } while (scale > 0); - result.lo = tmpNum[0]; - result.mid = tmpNum[1]; - result.hi = tmpNum[2]; + result.ulo = tmpNum[0]; + result.umid = tmpNum[1]; + result.uhi = tmpNum[2]; result.Scale = 0; return remainder; @@ -1255,7 +1255,7 @@ private static uint DecFixInt(ref Decimal input, ref Decimal result) //********************************************************************** internal static void VarCyFromDec(ref Decimal pdecIn, out long pcyOut) { - if (!Decimal.IsValid(pdecIn.flags)) + if (!Decimal.IsValid(pdecIn.uflags)) throw new OverflowException(SR.Overflow_Currency); Split64 sdlTmp = default(Split64); @@ -2388,9 +2388,9 @@ internal static void VarDecRound(ref Decimal input, int decimals, ref Decimal re scale = input.Scale - decimals; if (scale > 0) { - tmpNum[0] = input.lo; - tmpNum[1] = input.mid; - tmpNum[2] = input.hi; + tmpNum[0] = input.ulo; + tmpNum[1] = input.umid; + tmpNum[2] = input.uhi; result.Sign = input.Sign; remainder = sticky = 0; @@ -2416,9 +2416,9 @@ internal static void VarDecRound(ref Decimal input, int decimals, ref Decimal re && ++tmpNum[1] == 0) ++tmpNum[2]; - result.lo = tmpNum[0]; - result.mid = tmpNum[1]; - result.hi = tmpNum[2]; + result.ulo = tmpNum[0]; + result.umid = tmpNum[1]; + result.uhi = tmpNum[2]; result.Scale = decimals; return; } @@ -2434,7 +2434,7 @@ internal static Decimal VarDecMod(ref Decimal d1, ref Decimal d2) // OleAut doesn't provide a VarDecMod. // In the operation x % y the sign of y does not matter. Result will have the sign of x. - d2.flags = (d2.flags & ~SignMask) | (d1.flags & SignMask); + d2.uflags = (d2.uflags & ~SignMask) | (d1.uflags & SignMask); // This piece of code is to work around the fact that Dividing a decimal with 28 digits number by decimal which causes @@ -2449,7 +2449,7 @@ internal static Decimal VarDecMod(ref Decimal d1, ref Decimal d2) if (d1 == 0) { // The sign of D1 will be wrong here. Fall through so that we still get a DivideByZeroException - d1.flags = (d1.flags & ~SignMask) | (d2.flags & SignMask); + d1.uflags = (d1.uflags & ~SignMask) | (d2.uflags & SignMask); } // Formula: d1 - (RoundTowardsZero(d1 / d2) * d2) @@ -2457,14 +2457,14 @@ internal static Decimal VarDecMod(ref Decimal d1, ref Decimal d2) Decimal multipliedResult = dividedResult * d2; Decimal result = d1 - multipliedResult; // See if the result has crossed 0 - if ((d1.flags & SignMask) != (result.flags & SignMask)) + if ((d1.uflags & SignMask) != (result.uflags & SignMask)) { if (NearNegativeZero <= result && result <= NearPositiveZero) { // Certain Remainder operations on decimals with 28 significant digits round // to [+-]0.000000000000000000000000001m instead of [+-]0m during the intermediate calculations. // 'zero' results just need their sign corrected. - result.flags = (result.flags & ~SignMask) | (d1.flags & SignMask); + result.uflags = (result.uflags & ~SignMask) | (d1.uflags & SignMask); } else { @@ -2487,17 +2487,17 @@ private static void InternalAddUInt32RawUnchecked(ref Decimal value, UInt32 i) { UInt32 v; UInt32 sum; - v = value.lo; + v = value.ulo; sum = v + i; - value.lo = sum; + value.ulo = sum; if (sum < v || sum < i) { - v = value.mid; + v = value.umid; sum = v + 1; - value.mid = sum; + value.umid = sum; if (sum < v || sum < 1) { - value.hi = value.hi + 1; + value.uhi = value.uhi + 1; } } } @@ -2509,22 +2509,22 @@ private static UInt32 InternalDivRemUInt32(ref Decimal value, UInt32 divisor) { UInt32 remainder = 0; UInt64 n; - if (value.hi != 0) + if (value.uhi != 0) { - n = value.hi; - value.hi = (UInt32)(n / divisor); + n = value.uhi; + value.uhi = (UInt32)(n / divisor); remainder = (UInt32)(n % divisor); } - if (value.mid != 0 || remainder != 0) + if (value.umid != 0 || remainder != 0) { - n = ((UInt64)remainder << 32) | value.mid; - value.mid = (UInt32)(n / divisor); + n = ((UInt64)remainder << 32) | value.umid; + value.umid = (UInt32)(n / divisor); remainder = (UInt32)(n % divisor); } - if (value.lo != 0 || remainder != 0) + if (value.ulo != 0 || remainder != 0) { - n = ((UInt64)remainder << 32) | value.lo; - value.lo = (UInt32)(n / divisor); + n = ((UInt64)remainder << 32) | value.ulo; + value.ulo = (UInt32)(n / divisor); remainder = (UInt32)(n % divisor); } return remainder; @@ -2573,17 +2573,17 @@ private static uint D32DivMod1E9(uint hi32, ref uint lo32) internal static uint DecDivMod1E9(ref Decimal value) { return D32DivMod1E9(D32DivMod1E9(D32DivMod1E9(0, - ref value.hi), - ref value.mid), - ref value.lo); + ref value.uhi), + ref value.umid), + ref value.ulo); } internal static void DecAddInt32(ref Decimal value, uint i) { - if (D32AddCarry(ref value.lo, i)) + if (D32AddCarry(ref value.ulo, i)) { - if (D32AddCarry(ref value.mid, 1)) - D32AddCarry(ref value.hi, 1); + if (D32AddCarry(ref value.umid, 1)) + D32AddCarry(ref value.uhi, 1); } } @@ -2615,16 +2615,16 @@ private static void DecShiftLeft(ref Decimal value) private static void DecAdd(ref Decimal value, Decimal d) { - if (D32AddCarry(ref value.lo, d.Low)) + if (D32AddCarry(ref value.ulo, d.Low)) { - if (D32AddCarry(ref value.mid, 1)) - D32AddCarry(ref value.hi, 1); + if (D32AddCarry(ref value.umid, 1)) + D32AddCarry(ref value.uhi, 1); } - if (D32AddCarry(ref value.mid, d.Mid)) - D32AddCarry(ref value.hi, 1); + if (D32AddCarry(ref value.umid, d.Mid)) + D32AddCarry(ref value.uhi, 1); - D32AddCarry(ref value.hi, d.High); + D32AddCarry(ref value.uhi, d.High); } #endregion diff --git a/src/System.Private.CoreLib/src/System/Decimal.cs b/src/System.Private.CoreLib/src/System/Decimal.cs index b23fc204b62..3c69dfc22b8 100644 --- a/src/System.Private.CoreLib/src/System/Decimal.cs +++ b/src/System.Private.CoreLib/src/System/Decimal.cs @@ -101,10 +101,10 @@ public partial struct Decimal : IFormattable, IComparable, IConvertible, ICompar // // NOTE: Do not change the order in which these fields are declared. The // native methods in this class rely on this particular order. - private uint flags; // Do not rename (binary serialization) - private uint hi; // Do not rename (binary serialization) - private uint lo; // Do not rename (binary serialization) - private uint mid; // Do not rename (binary serialization) + private uint uflags; // Do not rename (binary serialization) + private uint uhi; // Do not rename (binary serialization) + private uint ulo; // Do not rename (binary serialization) + private uint umid; // Do not rename (binary serialization) // Constructs a zero Decimal. @@ -124,16 +124,16 @@ public Decimal(int value) int value_copy = value; if (value_copy >= 0) { - flags = 0; + uflags = 0; } else { - flags = SignMask; + uflags = SignMask; value_copy = -value_copy; } - lo = (uint)value_copy; - mid = 0; - hi = 0; + ulo = (uint)value_copy; + umid = 0; + uhi = 0; } // Constructs a Decimal from an unsigned integer value. @@ -141,10 +141,10 @@ public Decimal(int value) [CLSCompliant(false)] public Decimal(uint value) { - flags = 0; - lo = value; - mid = 0; - hi = 0; + uflags = 0; + ulo = value; + umid = 0; + uhi = 0; } // Constructs a Decimal from a long value. @@ -156,16 +156,16 @@ public Decimal(long value) long value_copy = value; if (value_copy >= 0) { - flags = 0; + uflags = 0; } else { - flags = SignMask; + uflags = SignMask; value_copy = -value_copy; } - lo = (uint)value_copy; - mid = (uint)(value_copy >> 32); - hi = 0; + ulo = (uint)value_copy; + umid = (uint)(value_copy >> 32); + uhi = 0; } // Constructs a Decimal from an unsigned long value. @@ -173,10 +173,10 @@ public Decimal(long value) [CLSCompliant(false)] public Decimal(ulong value) { - flags = 0; - lo = (uint)value; - mid = (uint)(value >> 32); - hi = 0; + uflags = 0; + ulo = (uint)value; + umid = (uint)(value >> 32); + uhi = 0; } // Constructs a Decimal from a float value. @@ -264,10 +264,10 @@ public static long ToOACurrency(Decimal value) // public Decimal(int[] bits) { - lo = 0; - mid = 0; - hi = 0; - flags = 0; + ulo = 0; + umid = 0; + uhi = 0; + uflags = 0; SetBits(bits); } @@ -281,10 +281,10 @@ private void SetBits(int[] bits) uint f = (uint)bits[3]; if (IsValid(f)) { - lo = (uint)bits[0]; - mid = (uint)bits[1]; - hi = (uint)bits[2]; - flags = f; + ulo = (uint)bits[0]; + umid = (uint)bits[1]; + uhi = (uint)bits[2]; + uflags = f; return; } } @@ -298,12 +298,12 @@ public Decimal(int lo, int mid, int hi, bool isNegative, byte scale) if (scale > 28) throw new ArgumentOutOfRangeException(nameof(scale), SR.ArgumentOutOfRange_DecimalScale); Contract.EndContractBlock(); - this.lo = (uint)lo; - this.mid = (uint)mid; - this.hi = (uint)hi; - flags = ((uint)scale) << 16; + this.ulo = (uint)lo; + this.umid = (uint)mid; + this.uhi = (uint)hi; + uflags = ((uint)scale) << 16; if (isNegative) - flags |= SignMask; + uflags |= SignMask; } void IDeserializationCallback.OnDeserialization(Object sender) @@ -325,10 +325,10 @@ private Decimal(int lo, int mid, int hi, int flags) { if ((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16)) { - this.lo = (uint)lo; - this.mid = (uint)mid; - this.hi = (uint)hi; - this.flags = (uint)flags; + this.ulo = (uint)lo; + this.umid = (uint)mid; + this.uhi = (uint)hi; + this.uflags = (uint)flags; return; } throw new ArgumentException(SR.Arg_DecBitCtor); @@ -340,7 +340,7 @@ private Decimal(int lo, int mid, int hi, int flags) // internal static Decimal Abs(Decimal d) { - return new Decimal((int)d.lo, (int)d.mid, (int)d.hi, (int)(d.flags & ~SignMask)); + return new Decimal((int)d.ulo, (int)d.umid, (int)d.uhi, (int)(d.uflags & ~SignMask)); } @@ -558,7 +558,7 @@ public static Boolean TryParse(String s, NumberStyles style, IFormatProvider pro // public static int[] GetBits(Decimal d) { - return new int[] { (int)d.lo, (int)d.mid, (int)d.hi, (int)d.flags }; + return new int[] { (int)d.ulo, (int)d.umid, (int)d.uhi, (int)d.uflags }; } // Returns the larger of two Decimal values. @@ -595,7 +595,7 @@ public static Decimal Multiply(Decimal d1, Decimal d2) // public static Decimal Negate(Decimal d) { - return new Decimal((int)d.lo, (int)d.mid, (int)d.hi, (int)(d.flags ^ SignMask)); + return new Decimal((int)d.ulo, (int)d.umid, (int)d.uhi, (int)(d.uflags ^ SignMask)); } // Rounds a Decimal value to a given number of decimal places. The value @@ -731,9 +731,9 @@ public static double ToDouble(Decimal d) public static int ToInt32(Decimal d) { if (d.Scale != 0) DecCalc.VarDecFix(ref d); - if (d.hi == 0 && d.mid == 0) + if (d.uhi == 0 && d.umid == 0) { - int i = (int)d.lo; + int i = (int)d.ulo; if (!d.Sign) { if (i >= 0) return i; @@ -754,9 +754,9 @@ public static int ToInt32(Decimal d) public static long ToInt64(Decimal d) { if (d.Scale != 0) DecCalc.VarDecFix(ref d); - if (d.hi == 0) + if (d.uhi == 0) { - long l = d.lo | (long)(int)d.mid << 32; + long l = d.ulo | (long)(int)d.umid << 32; if (!d.Sign) { if (l >= 0) return l; @@ -798,10 +798,10 @@ public static ushort ToUInt16(Decimal value) public static uint ToUInt32(Decimal d) { if (d.Scale != 0) DecCalc.VarDecFix(ref d); - if (d.hi == 0 && d.mid == 0) + if (d.uhi == 0 && d.umid == 0) { - if (!d.Sign || d.lo == 0) - return d.lo; + if (!d.Sign || d.ulo == 0) + return d.ulo; } throw new OverflowException(SR.Overflow_UInt32); } @@ -814,9 +814,9 @@ public static uint ToUInt32(Decimal d) public static ulong ToUInt64(Decimal d) { if (d.Scale != 0) DecCalc.VarDecFix(ref d); - if (d.hi == 0) + if (d.uhi == 0) { - ulong l = (ulong)d.lo | ((ulong)d.mid << 32); + ulong l = (ulong)d.ulo | ((ulong)d.umid << 32); if (!d.Sign || l == 0) return l; } From cb2f71e037d4de175ec8ecbdd613734692bb62aa Mon Sep 17 00:00:00 2001 From: Atsushi Kanamori Date: Thu, 8 Jun 2017 09:50:58 -0700 Subject: [PATCH 2/3] Add the serialization-visible signed fields under the original names. --- .../src/System/Decimal.cs | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/System.Private.CoreLib/src/System/Decimal.cs b/src/System.Private.CoreLib/src/System/Decimal.cs index 3c69dfc22b8..ecbede4a16b 100644 --- a/src/System.Private.CoreLib/src/System/Decimal.cs +++ b/src/System.Private.CoreLib/src/System/Decimal.cs @@ -52,7 +52,7 @@ namespace System // Decimal throws an OverflowException if the value is not within // the range of the Decimal type. [Serializable] - [StructLayout(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Explicit)] public partial struct Decimal : IFormattable, IComparable, IConvertible, IComparable, IEquatable, IDeserializationCallback { // Sign mask for the flags field. A value of zero in this bit indicates a @@ -99,13 +99,27 @@ public partial struct Decimal : IFormattable, IComparable, IConvertible, ICompar // and finally bit 31 indicates the sign of the Decimal value, 0 meaning // positive and 1 meaning negative. // - // NOTE: Do not change the order in which these fields are declared. The - // native methods in this class rely on this particular order. - private uint uflags; // Do not rename (binary serialization) - private uint uhi; // Do not rename (binary serialization) - private uint ulo; // Do not rename (binary serialization) - private uint umid; // Do not rename (binary serialization) - + // NOTE: Do not change the offsets of these fields. This structure maps to the OleAut DECIMAL structure + // and can be passed as such in P/Invokes. + [FieldOffset(0)] + private int flags; // Do not rename (binary serialization) + [FieldOffset(4)] + private int hi; // Do not rename (binary serialization) + [FieldOffset(8)] + private int lo; // Do not rename (binary serialization) + [FieldOffset(12)] + private int mid; // Do not rename (binary serialization) + + // NOTE: This set of fields overlay the ones exposed to serialization (which have to be signed ints for serialization compat.) + // The code inside Decimal was ported from C++ and expect unsigned values. + [FieldOffset(0), NonSerialized] + private uint uflags; + [FieldOffset(4), NonSerialized] + private uint uhi; + [FieldOffset(8), NonSerialized] + private uint ulo; + [FieldOffset(12), NonSerialized] + private uint umid; // Constructs a zero Decimal. //public Decimal() { From f46f8867c9136b572a632ee785a2f35d189311f7 Mon Sep 17 00:00:00 2001 From: Atsushi Kanamori Date: Thu, 8 Jun 2017 09:51:44 -0700 Subject: [PATCH 3/3] Opportunistically eliminate casts using the non-'u' fields. --- .../src/System/Decimal.DecCalc.cs | 2 +- .../src/System/Decimal.cs | 44 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs b/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs index 09f51be9694..27844daf605 100644 --- a/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs +++ b/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs @@ -1190,7 +1190,7 @@ private static void RoundUp(uint[] rgulQuo, ref int iScale) // private static Decimal Abs(Decimal d) { - return new Decimal((int)d.ulo, (int)d.umid, (int)d.uhi, (int)(d.uflags & ~SignMask)); + return new Decimal(d.lo, d.mid, d.hi, (int)(d.uflags & ~SignMask)); } /*** diff --git a/src/System.Private.CoreLib/src/System/Decimal.cs b/src/System.Private.CoreLib/src/System/Decimal.cs index ecbede4a16b..1532a0a1397 100644 --- a/src/System.Private.CoreLib/src/System/Decimal.cs +++ b/src/System.Private.CoreLib/src/System/Decimal.cs @@ -145,9 +145,9 @@ public Decimal(int value) uflags = SignMask; value_copy = -value_copy; } - ulo = (uint)value_copy; - umid = 0; - uhi = 0; + lo = value_copy; + mid = 0; + hi = 0; } // Constructs a Decimal from an unsigned integer value. @@ -278,10 +278,10 @@ public static long ToOACurrency(Decimal value) // public Decimal(int[] bits) { - ulo = 0; - umid = 0; - uhi = 0; - uflags = 0; + lo = 0; + mid = 0; + hi = 0; + flags = 0; SetBits(bits); } @@ -295,9 +295,9 @@ private void SetBits(int[] bits) uint f = (uint)bits[3]; if (IsValid(f)) { - ulo = (uint)bits[0]; - umid = (uint)bits[1]; - uhi = (uint)bits[2]; + lo = bits[0]; + mid = bits[1]; + hi = bits[2]; uflags = f; return; } @@ -312,9 +312,9 @@ public Decimal(int lo, int mid, int hi, bool isNegative, byte scale) if (scale > 28) throw new ArgumentOutOfRangeException(nameof(scale), SR.ArgumentOutOfRange_DecimalScale); Contract.EndContractBlock(); - this.ulo = (uint)lo; - this.umid = (uint)mid; - this.uhi = (uint)hi; + this.lo = lo; + this.mid = mid; + this.hi = hi; uflags = ((uint)scale) << 16; if (isNegative) uflags |= SignMask; @@ -339,10 +339,10 @@ private Decimal(int lo, int mid, int hi, int flags) { if ((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16)) { - this.ulo = (uint)lo; - this.umid = (uint)mid; - this.uhi = (uint)hi; - this.uflags = (uint)flags; + this.lo = lo; + this.mid = mid; + this.hi = hi; + this.flags = flags; return; } throw new ArgumentException(SR.Arg_DecBitCtor); @@ -354,7 +354,7 @@ private Decimal(int lo, int mid, int hi, int flags) // internal static Decimal Abs(Decimal d) { - return new Decimal((int)d.ulo, (int)d.umid, (int)d.uhi, (int)(d.uflags & ~SignMask)); + return new Decimal(d.lo, d.mid, d.hi, (int)(d.uflags & ~SignMask)); } @@ -572,7 +572,7 @@ public static Boolean TryParse(String s, NumberStyles style, IFormatProvider pro // public static int[] GetBits(Decimal d) { - return new int[] { (int)d.ulo, (int)d.umid, (int)d.uhi, (int)d.uflags }; + return new int[] { d.lo, d.mid, d.hi, d.flags }; } // Returns the larger of two Decimal values. @@ -609,7 +609,7 @@ public static Decimal Multiply(Decimal d1, Decimal d2) // public static Decimal Negate(Decimal d) { - return new Decimal((int)d.ulo, (int)d.umid, (int)d.uhi, (int)(d.uflags ^ SignMask)); + return new Decimal(d.lo, d.mid, d.hi, (int)(d.uflags ^ SignMask)); } // Rounds a Decimal value to a given number of decimal places. The value @@ -745,9 +745,9 @@ public static double ToDouble(Decimal d) public static int ToInt32(Decimal d) { if (d.Scale != 0) DecCalc.VarDecFix(ref d); - if (d.uhi == 0 && d.umid == 0) + if (d.hi == 0 && d.mid == 0) { - int i = (int)d.ulo; + int i = d.lo; if (!d.Sign) { if (i >= 0) return i;