Refactor: outline single-byte buffer grow for hot path

Refactored WriteByte, WriteVarUInt, and WriteVarULong to use a new GrowOne helper for single-byte buffer growth. This moves the Output.Grow call out of the hot path, improving inlining and serialization performance for frequent single-byte writes. Added detailed comments explaining the rationale and AOT benefits.
This commit is contained in:
Loretta 2026-05-13 20:01:11 +02:00
parent 72dab46bde
commit b849beb2ee
1 changed files with 14 additions and 6 deletions

View File

@ -388,11 +388,21 @@ public static partial class AcBinarySerializer
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteByte(byte value) public void WriteByte(byte value)
{ {
if (_position >= _bufferEnd) if (_position >= _bufferEnd) GrowOne();
Output.Grow(ref _buffer, ref _position, ref _bufferEnd, 1);
_buffer[_position++] = value; _buffer[_position++] = value;
} }
/// <summary>
/// Cold-path single-byte grow helper. Outlined from the hot-path 1-byte writers
/// (<see cref="WriteByte"/>, <see cref="WriteVarUInt"/> / <see cref="WriteVarULong"/> fast-paths)
/// so the inliner cost-models the hot path WITHOUT the 4-ref-arg <c>Output.Grow</c> call's
/// argument-prep IL. This keeps the per-property hot-path tight enough for AOT to inline the
/// write into the source-gen <c>WriteProperties</c> body across many call-sites — the cumulative
/// gain shows up on graph-heavy cells where every leaf serialises ~6 primitive properties.
/// </summary>
[MethodImpl(MethodImplOptions.NoInlining)]
private void GrowOne() => Output.Grow(ref _buffer, ref _position, ref _bufferEnd, 1);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteTwoBytes(byte b1, byte b2) public void WriteTwoBytes(byte b1, byte b2)
{ {
@ -464,8 +474,7 @@ public static partial class AcBinarySerializer
//if (FastWire) { WriteRaw(value); return; } //if (FastWire) { WriteRaw(value); return; }
if (value < 0x80) if (value < 0x80)
{ {
if (_position >= _bufferEnd) if (_position >= _bufferEnd) GrowOne();
Output.Grow(ref _buffer, ref _position, ref _bufferEnd, 1);
_buffer[_position++] = (byte)value; _buffer[_position++] = (byte)value;
return; return;
} }
@ -531,8 +540,7 @@ public static partial class AcBinarySerializer
//if (FastWire) { WriteRaw(value); return; } //if (FastWire) { WriteRaw(value); return; }
if (value < 0x80) if (value < 0x80)
{ {
if (_position >= _bufferEnd) if (_position >= _bufferEnd) GrowOne();
Output.Grow(ref _buffer, ref _position, ref _bufferEnd, 1);
_buffer[_position++] = (byte)value; _buffer[_position++] = (byte)value;
return; return;
} }