Skip to content

Commit e833446

Browse files
authored
Performance | netcore: use new decimal.GetBits overload (#3732)
* Use new decimal.GetBits overload in .NET * Correct indentation of #pragma warning * Remove now-defunct _decimalBits
1 parent ad5687e commit e833446

File tree

4 files changed

+68
-35
lines changed

4 files changed

+68
-35
lines changed

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBuffer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1352,7 +1352,7 @@ internal void SetToDateTime2(DateTime dateTime, byte scale)
13521352
}
13531353
#endif
13541354

1355-
internal void SetToDecimal(byte precision, byte scale, bool positive, int[] bits)
1355+
internal void SetToDecimal(byte precision, byte scale, bool positive, ReadOnlySpan<int> bits)
13561356
{
13571357
Debug.Assert(IsEmpty, "setting value a second time?");
13581358
_value._numericInfo._precision = precision;

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2251,7 +2251,13 @@ private byte ValueScaleCore(object value)
22512251
{
22522252
if (value is decimal decimalValue)
22532253
{
2254-
return (byte)((decimal.GetBits(decimalValue)[3] & 0x00ff0000) >> 0x10);
2254+
#if NET
2255+
Span<int> decimalBits = stackalloc int[4];
2256+
decimal.GetBits(decimalValue, decimalBits);
2257+
#else
2258+
int[] decimalBits = decimal.GetBits(decimalValue);
2259+
#endif
2260+
return (byte)((decimalBits[3] & 0x00ff0000) >> 0x10);
22552261
}
22562262
return 0;
22572263
}

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParser.cs

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6780,7 +6780,7 @@ internal bool DeserializeUnencryptedValue(SqlBuffer value, byte[] unencryptedByt
67806780

67816781
// Now read the 4 next integers which contain the actual value.
67826782
length = checked((int)length - 1);
6783-
int[] bits = new int[4];
6783+
Span<int> bits = stackalloc int[4];
67846784
int decLength = length >> 2;
67856785
ReadOnlySpan<byte> span = unencryptedBytes.AsSpan();
67866786
for (int i = 0; i < decLength; i++)
@@ -7700,8 +7700,15 @@ internal Task WriteSqlVariantValue(object value, int length, int offset, TdsPars
77007700

77017701
case TdsEnums.SQLNUMERICN:
77027702
{
7703+
#if NET
7704+
Span<int> decimalBits = stackalloc int[4];
7705+
decimal.GetBits((decimal)value, decimalBits);
7706+
#else
7707+
int[] decimalBits = decimal.GetBits((decimal)value);
7708+
#endif
7709+
77037710
stateObj.WriteByte(mt.Precision); //propbytes: precision
7704-
stateObj.WriteByte((byte)((decimal.GetBits((decimal)value)[3] & 0x00ff0000) >> 0x10)); // propbytes: scale
7711+
stateObj.WriteByte((byte)((decimalBits[3] & 0x00ff0000) >> 0x10)); // propbytes: scale
77057712
WriteDecimal((decimal)value, stateObj);
77067713
break;
77077714
}
@@ -7862,9 +7869,15 @@ internal Task WriteSqlVariantDataRowValue(object value, TdsParserStateObject sta
78627869

78637870
case TdsEnums.SQLNUMERICN:
78647871
{
7872+
#if NET
7873+
Span<int> decimalBits = stackalloc int[4];
7874+
decimal.GetBits((decimal)value, decimalBits);
7875+
#else
7876+
int[] decimalBits = decimal.GetBits((decimal)value);
7877+
#endif
78657878
WriteSqlVariantHeader(21, metatype.TDSType, metatype.PropBytes, stateObj);
78667879
stateObj.WriteByte(metatype.Precision); //propbytes: precision
7867-
stateObj.WriteByte((byte)((decimal.GetBits((decimal)value)[3] & 0x00ff0000) >> 0x10)); // propbytes: scale
7880+
stateObj.WriteByte((byte)((decimalBits[3] & 0x00ff0000) >> 0x10)); // propbytes: scale
78687881
WriteDecimal((decimal)value, stateObj);
78697882
break;
78707883
}
@@ -7921,7 +7934,12 @@ private byte[] SerializeSqlMoney(SqlMoney value, int length, TdsParserStateObjec
79217934
private void WriteSqlMoney(SqlMoney value, int length, TdsParserStateObject stateObj)
79227935
{
79237936
// UNDONE: can I use SqlMoney.ToInt64()?
7937+
#if NET
7938+
Span<int> bits = stackalloc int[4];
7939+
decimal.GetBits(value.Value, bits);
7940+
#else
79247941
int[] bits = decimal.GetBits(value.Value);
7942+
#endif
79257943

79267944
// this decimal should be scaled by 10000 (regardless of what the incoming decimal was scaled by)
79277945
bool isNeg = (0 != (bits[3] & unchecked((int)0x80000000)));
@@ -7954,7 +7972,12 @@ private void WriteSqlMoney(SqlMoney value, int length, TdsParserStateObject stat
79547972
private byte[] SerializeCurrency(Decimal value, int length, TdsParserStateObject stateObj)
79557973
{
79567974
SqlMoney m = new SqlMoney(value);
7957-
int[] bits = Decimal.GetBits(m.Value);
7975+
#if NET
7976+
Span<int> bits = stackalloc int[4];
7977+
decimal.GetBits(m.Value, bits);
7978+
#else
7979+
int[] bits = decimal.GetBits(m.Value);
7980+
#endif
79587981

79597982
// this decimal should be scaled by 10000 (regardless of what the incoming decimal was scaled by)
79607983
bool isNeg = (0 != (bits[3] & unchecked((int)0x80000000)));
@@ -7999,7 +8022,12 @@ private byte[] SerializeCurrency(Decimal value, int length, TdsParserStateObject
79998022
private void WriteCurrency(decimal value, int length, TdsParserStateObject stateObj)
80008023
{
80018024
SqlMoney m = new SqlMoney(value);
8025+
#if NET
8026+
Span<int> bits = stackalloc int[4];
8027+
decimal.GetBits(m.Value, bits);
8028+
#else
80028029
int[] bits = decimal.GetBits(m.Value);
8030+
#endif
80038031

80048032
// this decimal should be scaled by 10000 (regardless of what the incoming decimal was scaled by)
80058033
bool isNeg = (0 != (bits[3] & unchecked((int)0x80000000)));
@@ -8136,8 +8164,8 @@ private TdsOperationStatus TryReadSqlDecimal(SqlBuffer value, int length, byte p
81368164

81378165
length = checked((int)length - 1);
81388166

8139-
int[] bits;
8140-
result = TryReadDecimalBits(length, stateObj, out bits);
8167+
Span<int> bits = stackalloc int[4];
8168+
result = TryReadDecimalBits(length, stateObj, bits);
81418169
if (result != TdsOperationStatus.Done)
81428170
{
81438171
return result;
@@ -8149,31 +8177,16 @@ private TdsOperationStatus TryReadSqlDecimal(SqlBuffer value, int length, byte p
81498177

81508178
// @devnote: length should be size of decimal without the sign
81518179
// @devnote: sign should have already been read off the wire
8152-
private TdsOperationStatus TryReadDecimalBits(int length, TdsParserStateObject stateObj, out int[] bits)
8180+
private TdsOperationStatus TryReadDecimalBits(int length, TdsParserStateObject stateObj, Span<int> bits)
81538181
{
8154-
bits = stateObj._decimalBits; // used alloc'd array if we have one already
8155-
int i;
8156-
8157-
if (bits == null)
8158-
{
8159-
bits = new int[4];
8160-
stateObj._decimalBits = bits;
8161-
}
8162-
else
8163-
{
8164-
for (i = 0; i < bits.Length; i++)
8165-
{
8166-
bits[i] = 0;
8167-
}
8168-
}
8169-
8182+
Debug.Assert(bits.Length == 4);
81708183
Debug.Assert((length > 0) &&
81718184
(length <= TdsEnums.MAX_NUMERIC_LEN - 1) &&
81728185
(length % 4 == 0), "decimal should have 4, 8, 12, or 16 bytes of data");
81738186

81748187
int decLength = length >> 2;
81758188

8176-
for (i = 0; i < decLength; i++)
8189+
for (int i = 0; i < decLength; i++)
81778190
{
81788191
// up to 16 bytes of data following the sign byte
81798192
TdsOperationStatus result = stateObj.TryReadInt32(out bits[i]);
@@ -8199,7 +8212,13 @@ internal static SqlDecimal AdjustSqlDecimalScale(SqlDecimal d, int newScale)
81998212

82008213
internal static decimal AdjustDecimalScale(decimal value, int newScale)
82018214
{
8202-
int oldScale = (decimal.GetBits(value)[3] & 0x00ff0000) >> 0x10;
8215+
#if NET
8216+
Span<int> decimalBits = stackalloc int[4];
8217+
decimal.GetBits(value, decimalBits);
8218+
#else
8219+
int[] decimalBits = decimal.GetBits(value);
8220+
#endif
8221+
int oldScale = (decimalBits[3] & 0x00ff0000) >> 0x10;
82038222

82048223
if (newScale != oldScale)
82058224
{
@@ -8281,7 +8300,12 @@ internal void WriteSqlDecimal(SqlDecimal d, TdsParserStateObject stateObj)
82818300

82828301
private byte[] SerializeDecimal(decimal value, TdsParserStateObject stateObj)
82838302
{
8284-
int[] decimalBits = Decimal.GetBits(value);
8303+
#if NET
8304+
Span<int> decimalBits = stackalloc int[4];
8305+
decimal.GetBits(value, decimalBits);
8306+
#else
8307+
int[] decimalBits = decimal.GetBits(value);
8308+
#endif
82858309
if (stateObj._bDecimalBytes == null)
82868310
{
82878311
stateObj._bDecimalBytes = new byte[17];
@@ -8336,8 +8360,12 @@ struct {
83368360

83378361
private void WriteDecimal(decimal value, TdsParserStateObject stateObj)
83388362
{
8339-
stateObj._decimalBits = decimal.GetBits(value);
8340-
Debug.Assert(stateObj._decimalBits != null, "decimalBits should be filled in at TdsExecuteRPC time");
8363+
#if NET
8364+
Span<int> decimalBits = stackalloc int[4];
8365+
decimal.GetBits(value, decimalBits);
8366+
#else
8367+
int[] decimalBits = decimal.GetBits(value);
8368+
#endif
83418369

83428370
/*
83438371
Returns a binary representation of a Decimal. The return value is an integer
@@ -8359,7 +8387,7 @@ struct {
83598387
*/
83608388

83618389
// write the sign (note that COM and SQL are opposite)
8362-
if (0x80000000 == (stateObj._decimalBits[3] & 0x80000000))
8390+
if ((decimalBits[3] & 0x80000000) == 0x80000000)
83638391
{
83648392
stateObj.WriteByte(0);
83658393
}
@@ -8368,9 +8396,9 @@ struct {
83688396
stateObj.WriteByte(1);
83698397
}
83708398

8371-
WriteInt(stateObj._decimalBits[0], stateObj);
8372-
WriteInt(stateObj._decimalBits[1], stateObj);
8373-
WriteInt(stateObj._decimalBits[2], stateObj);
8399+
WriteInt(decimalBits[0], stateObj);
8400+
WriteInt(decimalBits[1], stateObj);
8401+
WriteInt(decimalBits[2], stateObj);
83748402
WriteInt(0, stateObj);
83758403
}
83768404

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,6 @@ private enum SnapshotStatus
223223
// TDS stream processing variables
224224
internal ulong _longlen; // plp data length indicator
225225
internal ulong _longlenleft; // Length of data left to read (64 bit lengths)
226-
internal int[] _decimalBits; // scratch buffer for decimal/numeric data
227226
internal byte[] _bTmp = new byte[TdsEnums.SQL2005_HEADER_LEN]; // Scratch buffer for misc use
228227
internal int _bTmpRead; // Counter for number of temporary bytes read
229228
internal Decoder _plpdecoder; // Decoder object to process plp character data

0 commit comments

Comments
 (0)