Skip to content

Commit 5dbdde9

Browse files
Add tests and improve binary XmlDictionaryReader performance (#73332)
* Read primitive types more efficient * Allow stream to read more than minimum number of required bytes * Remove pinning and pointer code from array reads * Remove bounds checks from remaing array reads * remove extra unchecked * cleanup code * Start adding tests * Add tests for binary XmlDictionaryReader * cleanup * revert back to old byte read * add test for arrays using "ref" enumeration * add guid test * Try to read while arrays from stream before processing * Write guid arrays as memory on LittleEndian platforms * Update tests to be independent of byte order * FIx bugs introduced in #71752 * Add missing Advance to prevent corruption of reader * Correctly read decimal values
1 parent 00f34fb commit 5dbdde9

File tree

6 files changed

+405
-210
lines changed

6 files changed

+405
-210
lines changed

src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryReader.cs

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Diagnostics.CodeAnalysis;
55
using System.IO;
6+
using System.Runtime.InteropServices;
67
using System.Runtime.Serialization;
78

89
namespace System.Xml
@@ -1250,10 +1251,7 @@ private unsafe int ReadArray(bool[] array, int offset, int count)
12501251
{
12511252
CheckArray(array, offset, count);
12521253
int actual = Math.Min(count, _arrayCount);
1253-
fixed (bool* items = &array[offset])
1254-
{
1255-
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
1256-
}
1254+
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
12571255
SkipArrayElements(actual);
12581256
return actual;
12591257
}
@@ -1276,10 +1274,7 @@ private unsafe int ReadArray(short[] array, int offset, int count)
12761274
{
12771275
CheckArray(array, offset, count);
12781276
int actual = Math.Min(count, _arrayCount);
1279-
fixed (short* items = &array[offset])
1280-
{
1281-
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
1282-
}
1277+
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
12831278
SkipArrayElements(actual);
12841279
return actual;
12851280
}
@@ -1302,10 +1297,7 @@ private unsafe int ReadArray(int[] array, int offset, int count)
13021297
{
13031298
CheckArray(array, offset, count);
13041299
int actual = Math.Min(count, _arrayCount);
1305-
fixed (int* items = &array[offset])
1306-
{
1307-
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
1308-
}
1300+
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
13091301
SkipArrayElements(actual);
13101302
return actual;
13111303
}
@@ -1328,10 +1320,7 @@ private unsafe int ReadArray(long[] array, int offset, int count)
13281320
{
13291321
CheckArray(array, offset, count);
13301322
int actual = Math.Min(count, _arrayCount);
1331-
fixed (long* items = &array[offset])
1332-
{
1333-
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
1334-
}
1323+
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
13351324
SkipArrayElements(actual);
13361325
return actual;
13371326
}
@@ -1354,10 +1343,7 @@ private unsafe int ReadArray(float[] array, int offset, int count)
13541343
{
13551344
CheckArray(array, offset, count);
13561345
int actual = Math.Min(count, _arrayCount);
1357-
fixed (float* items = &array[offset])
1358-
{
1359-
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
1360-
}
1346+
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
13611347
SkipArrayElements(actual);
13621348
return actual;
13631349
}
@@ -1380,10 +1366,7 @@ private unsafe int ReadArray(double[] array, int offset, int count)
13801366
{
13811367
CheckArray(array, offset, count);
13821368
int actual = Math.Min(count, _arrayCount);
1383-
fixed (double* items = &array[offset])
1384-
{
1385-
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
1386-
}
1369+
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
13871370
SkipArrayElements(actual);
13881371
return actual;
13891372
}
@@ -1406,10 +1389,7 @@ private unsafe int ReadArray(decimal[] array, int offset, int count)
14061389
{
14071390
CheckArray(array, offset, count);
14081391
int actual = Math.Min(count, _arrayCount);
1409-
fixed (decimal* items = &array[offset])
1410-
{
1411-
BufferReader.UnsafeReadArray((byte*)items, (byte*)&items[actual]);
1412-
}
1392+
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
14131393
SkipArrayElements(actual);
14141394
return actual;
14151395
}
@@ -1433,9 +1413,11 @@ private int ReadArray(DateTime[] array, int offset, int count)
14331413
{
14341414
CheckArray(array, offset, count);
14351415
int actual = Math.Min(count, _arrayCount);
1436-
for (int i = 0; i < actual; i++)
1416+
// Try to read in whole array, but don't fail if not possible
1417+
BufferReader.GetBuffer(actual * ValueHandleLength.DateTime, out _, out _);
1418+
foreach (ref DateTime item in array.AsSpan(offset, actual))
14371419
{
1438-
array[offset + i] = BufferReader.ReadDateTime();
1420+
item = BufferReader.ReadDateTime();
14391421
}
14401422
SkipArrayElements(actual);
14411423
return actual;
@@ -1460,9 +1442,18 @@ private int ReadArray(Guid[] array, int offset, int count)
14601442
{
14611443
CheckArray(array, offset, count);
14621444
int actual = Math.Min(count, _arrayCount);
1463-
for (int i = 0; i < actual; i++)
1445+
if (BitConverter.IsLittleEndian)
14641446
{
1465-
array[offset + i] = BufferReader.ReadGuid();
1447+
BufferReader.ReadRawArrayBytes(array.AsSpan(offset, actual));
1448+
}
1449+
else
1450+
{
1451+
// Try to read in whole array, but don't fail if not possible
1452+
BufferReader.GetBuffer(actual * ValueHandleLength.Guid, out _, out _);
1453+
foreach (ref Guid item in array.AsSpan(offset, actual))
1454+
{
1455+
item = BufferReader.ReadGuid();
1456+
}
14661457
}
14671458
SkipArrayElements(actual);
14681459
return actual;
@@ -1487,9 +1478,11 @@ private int ReadArray(TimeSpan[] array, int offset, int count)
14871478
{
14881479
CheckArray(array, offset, count);
14891480
int actual = Math.Min(count, _arrayCount);
1490-
for (int i = 0; i < actual; i++)
1481+
// Try to read in whole array, but don't fail if not possible
1482+
BufferReader.GetBuffer(actual * ValueHandleLength.TimeSpan, out _, out _);
1483+
foreach (ref TimeSpan item in array.AsSpan(offset, actual))
14911484
{
1492-
array[offset + i] = BufferReader.ReadTimeSpan();
1485+
item = BufferReader.ReadTimeSpan();
14931486
}
14941487
SkipArrayElements(actual);
14951488
return actual;

0 commit comments

Comments
 (0)