Skip to content

Commit 03f850f

Browse files
authored
fix: Fixes sending packets and sidesteps a major issue with stackalloc and PGO in .NET 8 (#1607)
### Summary - Works around a sneaky edge case bug in the JIT with stackalloc where sometimes the buffer is not zero'd. - Fixes SendDisplayBoatHS - Fixes sending health bars in the `SendEverything()` logic. - Fixes a bug in sizing for some string helper functions. ### Developer Note We are enabled `SkipLocalsInit` - do not rely on `stackalloc` to be zero'd. To zero the buffer, use `span.Clear();` Closes #1606
1 parent 79ba1ea commit 03f850f

File tree

18 files changed

+67
-76
lines changed

18 files changed

+67
-76
lines changed

Directory.Build.props

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
<DefineConstants Condition="'$(IsOSX)'=='true' OR '$(IsLinux)'=='true'">UNIX</DefineConstants>
2828
<DefineConstants Condition="'$(IsX64)'=='true'">CPU_X64</DefineConstants>
2929
<DefineConstants Condition="'$(IsArm64)'=='true'">CPU_ARM64</DefineConstants>
30-
<DefineConstants Condition="'$(SkipLocalsInitAttribute)'=='true'">NO_LOCAL_INIT</DefineConstants>
3130
<DefineConstants>MUO</DefineConstants>
3231
<GitVersionBaseDirectory>$(SolutionDir)</GitVersionBaseDirectory>
3332
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>

Projects/Server/Json/Converters/Point2DConverter.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ namespace Server.Json;
2121

2222
public class Point2DConverter : JsonConverter<Point2D>
2323
{
24-
private Point2D DeserializeArray(ref Utf8JsonReader reader)
24+
private static Point2D DeserializeArray(ref Utf8JsonReader reader)
2525
{
2626
Span<int> data = stackalloc int[2];
27+
data.Clear();
2728
var count = 0;
2829

2930
while (true)
@@ -53,9 +54,10 @@ private Point2D DeserializeArray(ref Utf8JsonReader reader)
5354
return new Point2D(data[0], data[1]);
5455
}
5556

56-
private Point2D DeserializeObj(ref Utf8JsonReader reader)
57+
private static Point2D DeserializeObj(ref Utf8JsonReader reader)
5758
{
5859
Span<int> data = stackalloc int[2];
60+
data.Clear();
5961

6062
while (true)
6163
{

Projects/Server/Json/Converters/Point3DConverter.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ namespace Server.Json;
2121

2222
public class Point3DConverter : JsonConverter<Point3D>
2323
{
24-
private Point3D DeserializeArray(ref Utf8JsonReader reader)
24+
private static Point3D DeserializeArray(ref Utf8JsonReader reader)
2525
{
2626
Span<int> data = stackalloc int[3];
27+
data.Clear();
28+
2729
var count = 0;
2830

2931
while (true)
@@ -53,9 +55,10 @@ private Point3D DeserializeArray(ref Utf8JsonReader reader)
5355
return new Point3D(data[0], data[1], data[2]);
5456
}
5557

56-
private Point3D DeserializeObj(ref Utf8JsonReader reader)
58+
private static Point3D DeserializeObj(ref Utf8JsonReader reader)
5759
{
5860
Span<int> data = stackalloc int[3];
61+
data.Clear();
5962

6063
while (true)
6164
{

Projects/Server/Json/Converters/Rectangle3DConverter.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ namespace Server.Json;
2121

2222
public class Rectangle3DConverter : JsonConverter<Rectangle3D>
2323
{
24-
private Rectangle3D DeserializeArray(ref Utf8JsonReader reader)
24+
private static Rectangle3D DeserializeArray(ref Utf8JsonReader reader)
2525
{
2626
Span<int> data = stackalloc int[6];
27+
data.Clear();
28+
2729
var count = 0;
2830

2931
while (true)
@@ -53,9 +55,10 @@ private Rectangle3D DeserializeArray(ref Utf8JsonReader reader)
5355
return new Rectangle3D(data[0], data[1], data[2], data[3], data[4], data[5]);
5456
}
5557

56-
private Rectangle3D DeserializeObj(ref Utf8JsonReader reader, JsonSerializerOptions options)
58+
private static Rectangle3D DeserializeObj(ref Utf8JsonReader reader, JsonSerializerOptions options)
5759
{
5860
Span<int> data = stackalloc int[6];
61+
data.Clear();
5962

6063
// 0 - xyzwhd, 1 - x1y1z1x2y2z2, 2 - start/end
6164
var objType = -1;

Projects/Server/Json/Converters/WorldLocationConverter.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ public class WorldLocationConverter : JsonConverter<WorldLocation>
2424
private static Point3DConverter _point3DConverter;
2525
private static MapConverter _mapConverter;
2626

27-
private WorldLocation DeserializeArray(ref Utf8JsonReader reader)
27+
private static WorldLocation DeserializeArray(ref Utf8JsonReader reader)
2828
{
2929
Span<int> data = stackalloc int[3];
30+
data.Clear();
31+
3032
var count = 0;
3133
var hasMap = false;
3234
Map map = null;
@@ -77,9 +79,11 @@ private WorldLocation DeserializeArray(ref Utf8JsonReader reader)
7779
return new WorldLocation(data[0], data[1], data[2], map);
7880
}
7981

80-
private WorldLocation DeserializeObj(ref Utf8JsonReader reader, JsonSerializerOptions options)
82+
private static WorldLocation DeserializeObj(ref Utf8JsonReader reader, JsonSerializerOptions options)
8183
{
8284
Span<int> data = stackalloc int[3];
85+
data.Clear();
86+
8387
var hasLoc = false;
8488
var hasXYZ = false;
8589
var hasMap = false;

Projects/Server/Mobiles/Mobile.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2721,9 +2721,9 @@ public virtual void ProcessDelta()
27212721
Span<byte> facialHairPacket = stackalloc byte[facialHairLength].InitializePacket();
27222722

27232723
const int cacheLength = OutgoingMobilePackets.MobileMovingPacketCacheByteLength;
2724-
const int width = OutgoingMobilePackets.MobileMovingPacketLength;
27252724

2726-
var mobileMovingCache = stackalloc byte[cacheLength].InitializePackets(width);
2725+
Span<byte> mobileMovingCache = stackalloc byte[cacheLength];
2726+
mobileMovingCache.Clear();
27272727

27282728
var ourState = m_NetState;
27292729

@@ -4369,9 +4369,9 @@ public virtual bool Move(Direction d)
43694369
if (moveClientQueue.Count > 0)
43704370
{
43714371
const int cacheLength = OutgoingMobilePackets.MobileMovingPacketCacheByteLength;
4372-
const int width = OutgoingMobilePackets.MobileMovingPacketLength;
43734372

4374-
var mobileMovingCache = stackalloc byte[cacheLength].InitializePackets(width);
4373+
Span<byte> mobileMovingCache = stackalloc byte[cacheLength];
4374+
mobileMovingCache.Clear();
43754375

43764376
while (moveClientQueue.Count > 0)
43774377
{
@@ -6923,8 +6923,14 @@ public void SendEverything()
69236923

69246924
if (ns.StygianAbyss)
69256925
{
6926-
ns.SendMobileHealthbar(m, Healthbar.Poison);
6927-
ns.SendMobileHealthbar(m, Healthbar.Yellow);
6926+
if (m.Blessed || m.YellowHealthbar)
6927+
{
6928+
ns.SendMobileHealthbar(m, Healthbar.Yellow);
6929+
}
6930+
else if (m.Poisoned)
6931+
{
6932+
ns.SendMobileHealthbar(m, Healthbar.Poison);
6933+
}
69286934
}
69296935

69306936
if (m.IsDeadBondedPet)

Projects/Server/Module.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
using System.Runtime.CompilerServices;
2+
3+
// Skips initializing stackalloc with zeros.
4+
[module: SkipLocalsInit]

Projects/Server/Network/PacketUtilities.cs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,7 @@ public static void WritePacketLength(this ref SpanWriter writer)
3535
[MethodImpl(MethodImplOptions.AggressiveInlining)]
3636
public static Span<byte> InitializePacket(this Span<byte> buffer)
3737
{
38-
#if NO_LOCAL_INIT
39-
if (buffer != null)
40-
{
41-
buffer[0] = 0;
42-
}
43-
#endif
44-
return buffer;
45-
}
46-
47-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
48-
public static Span<byte> InitializePackets(this Span<byte> buffer, int width)
49-
{
50-
#if NO_LOCAL_INIT
51-
for (var i = 0; i < buffer.Length; i += width)
52-
{
53-
buffer[i] = 0;
54-
}
55-
#endif
38+
buffer[0] = 0;
5639
return buffer;
5740
}
5841
}

Projects/Server/Network/Packets/OutgoingEntityPackets.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515

1616
using System;
1717
using System.Buffers;
18+
using System.Buffers.Binary;
19+
using System.Runtime.CompilerServices;
1820
using Server.Items;
21+
using Server.Text;
1922

2023
namespace Server.Network;
2124

@@ -25,6 +28,7 @@ public static class OutgoingEntityPackets
2528
public const int RemoveEntityLength = 5;
2629
public const int MaxWorldEntityPacketLength = 26;
2730

31+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2832
public static void CreateOPLInfo(Span<byte> buffer, Item item) =>
2933
CreateOPLInfo(buffer, item.Serial, item.PropertyList.Hash);
3034

@@ -41,6 +45,7 @@ public static void CreateOPLInfo(Span<byte> buffer, Serial serial, int hash)
4145
writer.Write(hash);
4246
}
4347

48+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
4449
public static void SendOPLInfo(this NetState ns, IObjectPropertyListEntity obj) =>
4550
ns.SendOPLInfo(obj.Serial, obj.PropertyList.Hash);
4651

Projects/Server/Network/Packets/OutgoingMobilePackets.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -604,9 +604,7 @@ public static void SendMobileIncoming(this NetState ns, Mobile beholder, Mobile
604604
}
605605

606606
Span<bool> layers = stackalloc bool[256];
607-
#if NO_LOCAL_INIT
608-
layers.Clear();
609-
#endif
607+
layers.Clear();
610608

611609
var eq = beheld.Items;
612610
var maxLength = 23 + (eq.Count + 2) * 9;

0 commit comments

Comments
 (0)