Skip to content

Commit 557ee98

Browse files
authored
Remove bunch of allocations caused by static arrays by favoring ReadOnlySpan<T> (#9230)
* remove bunch of allocations caused by static arrays, fix ineffective codegens * first call references a property, lets unify that * address PR feedback from miloush, shave off few instructions each call * minor format fix, lets make the pointer type clear * fix failing CI build because it still targets net472 (net9 local build works fine)
1 parent 59a761b commit 557ee98

File tree

24 files changed

+154
-205
lines changed

24 files changed

+154
-205
lines changed

src/Microsoft.DotNet.Wpf/src/Common/Graphics/wgx_exports.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ static MILGuidData()
344344

345345
internal static readonly Guid GUID_ContainerFormatWmp = new Guid(0x57a37caa, 0x367a, 0x4540, 0x91, 0x6b, 0xf1, 0x83, 0xc5, 0x09, 0x3a, 0x4b);
346346

347-
internal static readonly byte[] GUID_VendorMicrosoft = new byte[] { 0xca, 0x49, 0xe7, 0xf0, 0xef, 0xed, 0x89, 0x45, 0xa7, 0x3a, 0xee, 0xe, 0x62, 0x6a, 0x2a, 0x2b };
347+
internal static ReadOnlySpan<byte> GUID_VendorMicrosoft => [0xca, 0x49, 0xe7, 0xf0, 0xef, 0xed, 0x89, 0x45, 0xa7, 0x3a, 0xee, 0xe, 0x62, 0x6a, 0x2a, 0x2b];
348348
}
349349
#endregion // Guids
350350
}

src/Microsoft.DotNet.Wpf/src/PresentationBuildTasks/Microsoft/Build/Tasks/Windows/GenerateTemporaryTargetAssembly.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -820,7 +820,7 @@ private static void ReplaceImplicitImports(XmlDocument xmlProjectDoc)
820820
XmlNode previousNodeImportProps = null;
821821
XmlNode previousNodeImportTargets = null;
822822

823-
foreach (string sdk in sdks.Split(_semicolonChar).Select(i => i.Trim()))
823+
foreach (string sdk in sdks.Split(s_semicolonChar).Select(i => i.Trim()))
824824
{
825825
// <Project Sdk="Microsoft.NET.Sdk">
826826
// <Project Sdk="My.Custom.Sdk/1.0.0">
@@ -952,7 +952,7 @@ static XmlNode CreateImportProjectSdkNode(XmlDocument xmlProjectDoc, string proj
952952

953953
private const string WPFTMP = "wpftmp";
954954

955-
private static readonly char[] _semicolonChar = new char[] { ';' };
955+
private static readonly char[] s_semicolonChar = [';'];
956956

957957
#endregion Private Fields
958958

src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/InkSerializedFormat/AlgoModule.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ private LZCodec LZCodec
457457
internal const byte DefaultBAACount = 8;
458458
internal const byte MaxBAACount = 10;
459459

460+
private static ReadOnlySpan<double> DefaultFirstSquareRoot => [1, 1, 1, 4, 9, 16, 36, 49];
460461

461-
private static readonly double[] DefaultFirstSquareRoot = { 1, 1, 1, 4, 9, 16, 36, 49};
462462
}
463463
}

src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/InkSerializedFormat/InkSerializer.cs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,13 @@ private void ExamineStreamHeader(Stream inkdata, out bool fBase64, out bool fGif
281281
return;
282282
}
283283

284-
private static readonly byte[] Base64HeaderBytes
285-
= new byte[]{(byte)'b',
286-
(byte)'a',
287-
(byte)'s',
288-
(byte)'e',
289-
(byte)'6',
290-
(byte)'4',
291-
(byte)':'};
284+
private static ReadOnlySpan<byte> Base64HeaderBytes => [(byte)'b',
285+
(byte)'a',
286+
(byte)'s',
287+
(byte)'e',
288+
(byte)'6',
289+
(byte)'4',
290+
(byte)':'];
292291

293292
#if OLD_ISF
294293
/// <summary>
@@ -2113,15 +2112,14 @@ private bool IsBase64Data(Stream data)
21132112
long currentPosition = data.Position;
21142113
try
21152114
{
2116-
byte[] isfBase64PrefixBytes = Base64HeaderBytes;
2117-
if (data.Length < isfBase64PrefixBytes.Length)
2115+
if (data.Length < Base64HeaderBytes.Length)
21182116
{
21192117
return false;
21202118
}
21212119

2122-
for (int x = 0; x < isfBase64PrefixBytes.Length; x++)
2120+
for (int x = 0; x < Base64HeaderBytes.Length; x++)
21232121
{
2124-
if ((byte)data.ReadByte() != isfBase64PrefixBytes[x])
2122+
if ((byte)data.ReadByte() != Base64HeaderBytes[x])
21252123
{
21262124
return false;
21272125
}

src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Shaping/Positioning.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,14 @@ internal struct ValueRecordTable
224224
const ushort XAdvanceDeviceFlag = 0x0040;
225225
const ushort YAdvanceDeviceFlag = 0x0080;
226226

227-
private static ushort[] BitCount =
228-
new ushort[16] { 0, 2, 2, 4, 2, 4, 4, 6, 2, 4, 4, 6, 4, 6, 6, 8 };
227+
private static ReadOnlySpan<ushort> BitCount => [0, 2, 2, 4,
228+
2, 4, 4, 6,
229+
2, 4, 4, 6,
230+
4, 6, 6, 8];
229231

230232
public static ushort Size(ushort Format)
231233
{
232-
return (ushort)(BitCount[Format&0x000F]+BitCount[(Format>>4)&0x000F]);
234+
return (ushort)(BitCount[Format & 0x000F] + BitCount[(Format >> 4) & 0x000F]);
233235
}
234236

235237
public void AdjustPos( FontTable Table,

src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Cursor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ private bool IsValidCursorType(CursorType cursorType)
354354

355355
private SafeHandle _cursorHandle;
356356

357-
private static readonly int[] CursorTypes = {
357+
private static ReadOnlySpan<int> CursorTypes => [
358358
0, // None
359359
NativeMethods.IDC_NO,
360360
NativeMethods.IDC_ARROW,
@@ -383,6 +383,6 @@ private bool IsValidCursorType(CursorType cursorType)
383383
NativeMethods.IDC_ARROW + 149, // ScrollSWCursor
384384
NativeMethods.IDC_ARROW + 150, // ScrollSECursor
385385
NativeMethods.IDC_ARROW + 151 // ArrowCDCursor
386-
};
386+
];
387387
}
388388
}

src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/EllipseGeometry.cs

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,10 @@ internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point center,
179179
{
180180
unsafe
181181
{
182-
Point * pPoints = stackalloc Point[(int)c_pointCount];
182+
Point* pPoints = stackalloc Point[(int)c_pointCount];
183183
EllipseGeometry.GetPointList(pPoints, c_pointCount, center, radiusX, radiusY);
184184

185-
fixed (byte *pTypes = EllipseGeometry.s_roundedPathTypes)
185+
fixed (byte* pTypes = RoundedPathTypes) //Merely retrieves the pointer to static PE data, no actual pinning occurs
186186
{
187187
rect = Geometry.GetBoundsHelper(
188188
pen,
@@ -206,10 +206,10 @@ internal override bool ContainsInternal(Pen pen, Point hitPoint, double toleranc
206206
{
207207
unsafe
208208
{
209-
Point *pPoints = stackalloc Point[(int)GetPointCount()];
209+
Point* pPoints = stackalloc Point[(int)GetPointCount()];
210210
EllipseGeometry.GetPointList(pPoints, GetPointCount(), Center, RadiusX, RadiusY);
211211

212-
fixed (byte* pTypes = GetTypeList())
212+
fixed (byte* pTypes = RoundedPathTypes) //Merely retrieves the pointer to static PE data, no actual pinning occurs
213213
{
214214
return ContainsInternal(
215215
pen,
@@ -383,9 +383,8 @@ private unsafe static void GetPointList(Point * points, uint pointsCount, Point
383383
points[8].Y = points[9].Y = points[10].Y = center.Y - radiusY;
384384
}
385385

386-
private byte[] GetTypeList() { return s_roundedPathTypes; }
387-
private uint GetPointCount() { return c_pointCount; }
388-
private uint GetSegmentCount() { return c_segmentCount; }
386+
private static uint GetPointCount() { return c_pointCount; }
387+
private static uint GetSegmentCount() { return c_segmentCount; }
389388

390389
#region Static Data
391390

@@ -396,18 +395,16 @@ private unsafe static void GetPointList(Point * points, uint pointsCount, Point
396395
private const UInt32 c_pointCount = 13;
397396

398397
private const byte c_smoothBezier = (byte)MILCoreSegFlags.SegTypeBezier |
399-
(byte)MILCoreSegFlags.SegIsCurved |
400-
(byte)MILCoreSegFlags.SegSmoothJoin;
401-
402-
private static readonly byte[] s_roundedPathTypes = {
403-
(byte)MILCoreSegFlags.SegTypeBezier |
404-
(byte)MILCoreSegFlags.SegIsCurved |
405-
(byte)MILCoreSegFlags.SegSmoothJoin |
406-
(byte)MILCoreSegFlags.SegClosed,
407-
c_smoothBezier,
408-
c_smoothBezier,
409-
c_smoothBezier
410-
};
398+
(byte)MILCoreSegFlags.SegIsCurved |
399+
(byte)MILCoreSegFlags.SegSmoothJoin;
400+
401+
private static ReadOnlySpan<byte> RoundedPathTypes => [(byte)MILCoreSegFlags.SegTypeBezier |
402+
(byte)MILCoreSegFlags.SegIsCurved |
403+
(byte)MILCoreSegFlags.SegSmoothJoin |
404+
(byte)MILCoreSegFlags.SegClosed,
405+
c_smoothBezier,
406+
c_smoothBezier,
407+
c_smoothBezier];
411408

412409
#endregion
413410
}

src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/LineGeometry.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point pt1, Poi
118118
pPoints[0] = pt1;
119119
pPoints[1] = pt2;
120120

121-
fixed (byte *pTypes = LineGeometry.s_lineTypes)
121+
fixed (byte* pTypes = LineTypes) //Merely retrieves the pointer to static PE data, no actual pinning occurs
122122
{
123123
return Geometry.GetBoundsHelper(
124124
pen,
@@ -140,11 +140,11 @@ internal override bool ContainsInternal(Pen pen, Point hitPoint, double toleranc
140140
{
141141
unsafe
142142
{
143-
Point *pPoints = stackalloc Point[2];
143+
Point* pPoints = stackalloc Point[2];
144144
pPoints[0] = StartPoint;
145145
pPoints[1] = EndPoint;
146146

147-
fixed (byte* pTypes = GetTypeList())
147+
fixed (byte* pTypes = LineTypes) //Merely retrieves the pointer to static PE data, no actual pinning occurs
148148
{
149149
return ContainsInternal(
150150
pen,
@@ -185,13 +185,11 @@ public override double GetArea(double tolerance, ToleranceType type)
185185
return 0.0;
186186
}
187187

188-
private byte[] GetTypeList() { return s_lineTypes; }
188+
private static ReadOnlySpan<byte> LineTypes => [(byte)MILCoreSegFlags.SegTypeLine];
189189

190-
private static byte[] s_lineTypes = new byte[] { (byte)MILCoreSegFlags.SegTypeLine };
190+
private static uint GetPointCount() { return c_pointCount; }
191191

192-
private uint GetPointCount() { return c_pointCount; }
193-
194-
private uint GetSegmentCount() { return c_segmentCount; }
192+
private static uint GetSegmentCount() { return c_segmentCount; }
195193

196194
/// <summary>
197195
/// GetAsPathGeometry - return a PathGeometry version of this Geometry

src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/RectangleGeometry.cs

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,10 @@ internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Rect rect, dou
220220
// We've checked that rect isn't empty above
221221
Invariant.Assert(pointCount != 0);
222222

223-
Point * pPoints = stackalloc Point[(int)pointCount];
223+
Point* pPoints = stackalloc Point[(int)pointCount];
224224
RectangleGeometry.GetPointList(pPoints, pointCount, rect, radiusX, radiusY);
225225

226-
fixed (byte *pTypes = RectangleGeometry.GetTypeList(rect, radiusX, radiusY))
226+
fixed (byte* pTypes = GetTypeList(rect, radiusX, radiusY)) //Merely retrieves the pointer to static PE data, no actual pinning occurs
227227
{
228228
boundingRect = Geometry.GetBoundsHelper(
229229
pen,
@@ -259,10 +259,10 @@ internal override bool ContainsInternal(Pen pen, Point hitPoint, double toleranc
259259

260260
unsafe
261261
{
262-
Point *pPoints = stackalloc Point[(int)pointCount];
262+
Point* pPoints = stackalloc Point[(int)pointCount];
263263
RectangleGeometry.GetPointList(pPoints, pointCount, rect, radiusX, radiusY);
264264

265-
fixed (byte* pTypes = GetTypeList(rect, radiusX, radiusY))
265+
fixed (byte* pTypes = GetTypeList(rect, radiusX, radiusY)) //Merely retrieves the pointer to static PE data, no actual pinning occurs
266266
{
267267
return ContainsInternal(
268268
pen,
@@ -510,19 +510,19 @@ private unsafe static void GetPointList(Point * points, uint pointsCount, Rect r
510510
}
511511
}
512512

513-
private static byte[] GetTypeList(Rect rect, double radiusX, double radiusY)
513+
private static ReadOnlySpan<byte> GetTypeList(Rect rect, double radiusX, double radiusY)
514514
{
515515
if (rect.IsEmpty)
516516
{
517517
return null;
518518
}
519519
else if (IsRounded(radiusX, radiusY))
520520
{
521-
return s_roundedPathTypes;
521+
return RoundedPathTypes;
522522
}
523523
else
524524
{
525-
return s_squaredPathTypes;
525+
return SquaredPathTypes;
526526
}
527527
}
528528

@@ -610,30 +610,28 @@ public override bool MayHaveCurves()
610610

611611
static private byte smoothLine = (byte)MILCoreSegFlags.SegTypeLine | (byte)MILCoreSegFlags.SegSmoothJoin;
612612

613-
static private byte[] s_roundedPathTypes = {
614-
(byte)MILCoreSegFlags.SegTypeBezier |
613+
private static ReadOnlySpan<byte> RoundedPathTypes => new byte[] {
614+
(byte)MILCoreSegFlags.SegTypeBezier |
615615
(byte)MILCoreSegFlags.SegIsCurved |
616-
(byte)MILCoreSegFlags.SegSmoothJoin |
616+
(byte)MILCoreSegFlags.SegSmoothJoin |
617617
(byte)MILCoreSegFlags.SegClosed,
618-
smoothLine,
618+
smoothLine,
619619
smoothBezier,
620-
smoothLine,
620+
smoothLine,
621621
smoothBezier,
622-
smoothLine,
622+
smoothLine,
623623
smoothBezier,
624-
smoothLine
624+
smoothLine
625625
};
626626

627627
// Squared
628628
private const UInt32 c_squaredSegmentCount = 4;
629629
private const UInt32 c_squaredPointCount = 5;
630630

631-
private static readonly byte[] s_squaredPathTypes = {
632-
(byte)MILCoreSegFlags.SegTypeLine | (byte)MILCoreSegFlags.SegClosed,
633-
(byte)MILCoreSegFlags.SegTypeLine,
634-
(byte)MILCoreSegFlags.SegTypeLine,
635-
(byte)MILCoreSegFlags.SegTypeLine
636-
};
631+
private static ReadOnlySpan<byte> SquaredPathTypes => [(byte)MILCoreSegFlags.SegTypeLine | (byte)MILCoreSegFlags.SegClosed,
632+
(byte)MILCoreSegFlags.SegTypeLine,
633+
(byte)MILCoreSegFlags.SegTypeLine,
634+
(byte)MILCoreSegFlags.SegTypeLine];
637635

638636
#endregion
639637
}

src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Anchoring/LocatorManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1370,7 +1370,7 @@ private class ResolvingLocatorState
13701370
private Hashtable _selectionProcessors;
13711371

13721372
// Potential separators for subtree processor class names
1373-
private static readonly Char[] Separators = new Char[] { ',', ' ', ';' };
1373+
private static ReadOnlySpan<char> Separators => [',', ' ', ';'];
13741374

13751375
// Optional store, used if passed in, otherwise we grab the service's store
13761376
private AnnotationStore _internalStore = null;

0 commit comments

Comments
 (0)