diff --git a/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs b/src/System.Private.CoreLib/src/System/Decimal.DecCalc.cs index e2267de5e0b..27844daf605 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(d.lo, d.mid, d.hi, (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..1532a0a1397 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 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) - + // 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() { @@ -124,14 +138,14 @@ 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; + lo = value_copy; mid = 0; hi = 0; } @@ -141,10 +155,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 +170,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 +187,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. @@ -281,10 +295,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; + lo = bits[0]; + mid = bits[1]; + hi = bits[2]; + uflags = f; return; } } @@ -298,12 +312,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.lo = lo; + this.mid = mid; + this.hi = hi; + uflags = ((uint)scale) << 16; if (isNegative) - flags |= SignMask; + uflags |= SignMask; } void IDeserializationCallback.OnDeserialization(Object sender) @@ -325,10 +339,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.lo = lo; + this.mid = mid; + this.hi = hi; + this.flags = flags; return; } throw new ArgumentException(SR.Arg_DecBitCtor); @@ -340,7 +354,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(d.lo, d.mid, d.hi, (int)(d.uflags & ~SignMask)); } @@ -558,7 +572,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[] { d.lo, d.mid, d.hi, d.flags }; } // Returns the larger of two Decimal values. @@ -595,7 +609,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(d.lo, d.mid, d.hi, (int)(d.uflags ^ SignMask)); } // Rounds a Decimal value to a given number of decimal places. The value @@ -733,7 +747,7 @@ public static int ToInt32(Decimal d) if (d.Scale != 0) DecCalc.VarDecFix(ref d); if (d.hi == 0 && d.mid == 0) { - int i = (int)d.lo; + int i = d.lo; if (!d.Sign) { if (i >= 0) return i; @@ -754,9 +768,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 +812,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 +828,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; }