optimize initialization of ParseContext
diff --git a/csharp/src/Google.Protobuf.Benchmarks/ParseMessagesBenchmark.cs b/csharp/src/Google.Protobuf.Benchmarks/ParseMessagesBenchmark.cs
index 3cd70e3..30f3e9e 100644
--- a/csharp/src/Google.Protobuf.Benchmarks/ParseMessagesBenchmark.cs
+++ b/csharp/src/Google.Protobuf.Benchmarks/ParseMessagesBenchmark.cs
@@ -195,7 +195,7 @@
public void ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
{
- var ctx = new ParseContext(multipleMessagesDataSequence);
+ ParseContext.Initialize(multipleMessagesDataSequence, out ParseContext ctx);
for (int i = 0; i < messageCount; i++)
{
var msg = factory();
diff --git a/csharp/src/Google.Protobuf.Benchmarks/ParseRawPrimitivesBenchmark.cs b/csharp/src/Google.Protobuf.Benchmarks/ParseRawPrimitivesBenchmark.cs
index 28c1be5..8d3e13a 100644
--- a/csharp/src/Google.Protobuf.Benchmarks/ParseRawPrimitivesBenchmark.cs
+++ b/csharp/src/Google.Protobuf.Benchmarks/ParseRawPrimitivesBenchmark.cs
@@ -105,7 +105,7 @@
[Arguments(5)]
public int ParseRawVarint32_ParseContext(int encodedSize)
{
- var ctx = CreateParseContext(varintInputBuffers[encodedSize]);
+ InitializeParseContext(varintInputBuffers[encodedSize], out ParseContext ctx);
int sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
@@ -149,7 +149,7 @@
[Arguments(10)]
public long ParseRawVarint64_ParseContext(int encodedSize)
{
- var ctx = CreateParseContext(varintInputBuffers[encodedSize]);
+ InitializeParseContext(varintInputBuffers[encodedSize], out ParseContext ctx);
long sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
@@ -175,7 +175,7 @@
public uint ParseFixed32_ParseContext()
{
const int encodedSize = sizeof(uint);
- var ctx = CreateParseContext(fixedIntInputBuffer);
+ InitializeParseContext(fixedIntInputBuffer, out ParseContext ctx);
uint sum = 0;
for (uint i = 0; i < BytesToParse / encodedSize; i++)
{
@@ -201,7 +201,7 @@
public ulong ParseFixed64_ParseContext()
{
const int encodedSize = sizeof(ulong);
- var ctx = CreateParseContext(fixedIntInputBuffer);
+ InitializeParseContext(fixedIntInputBuffer, out ParseContext ctx);
ulong sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
@@ -227,7 +227,7 @@
public float ParseRawFloat_ParseContext()
{
const int encodedSize = sizeof(float);
- var ctx = CreateParseContext(floatInputBuffer);
+ InitializeParseContext(floatInputBuffer, out ParseContext ctx);
float sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
@@ -253,7 +253,7 @@
public double ParseRawDouble_ParseContext()
{
const int encodedSize = sizeof(double);
- var ctx = CreateParseContext(doubleInputBuffer);
+ InitializeParseContext(doubleInputBuffer, out ParseContext ctx);
double sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
@@ -262,9 +262,9 @@
return sum;
}
- private static ParseContext CreateParseContext(byte[] buffer)
+ private static void InitializeParseContext(byte[] buffer, out ParseContext ctx)
{
- return new ParseContext(new ReadOnlySequence<byte>(buffer));
+ ParseContext.Initialize(new ReadOnlySequence<byte>(buffer), out ctx);
}
private static byte[] CreateBufferWithRandomVarints(Random random, int valueCount, int encodedSize, int paddingValueCount)
diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs
index 4c9234d..dc36199 100644
--- a/csharp/src/Google.Protobuf/CodedInputStream.cs
+++ b/csharp/src/Google.Protobuf/CodedInputStream.cs
@@ -431,7 +431,7 @@
public void ReadMessage(IMessage builder)
{
var span = new ReadOnlySpan<byte>(buffer);
- var ctx = new ParseContext(ref span, ref state);
+ ParseContext.Initialize(ref span, ref state, out ParseContext ctx);
try
{
ParsingPrimitivesMessages.ReadMessage(ref ctx, builder);
@@ -447,7 +447,7 @@
/// </summary>
public void ReadGroup(IMessage builder)
{
- var ctx = new ParseContext(this);
+ ParseContext.Initialize(this, out ParseContext ctx);
try
{
ParsingPrimitivesMessages.ReadGroup(ref ctx, builder);
@@ -691,7 +691,7 @@
/// </summary>
public void ReadRawMessage(IMessage message)
{
- var ctx = new ParseContext(this);
+ ParseContext.Initialize(this, out ParseContext ctx);
try
{
ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message);
diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
index 3ea2a68..a2604f1 100644
--- a/csharp/src/Google.Protobuf/Collections/MapField.cs
+++ b/csharp/src/Google.Protobuf/Collections/MapField.cs
@@ -713,7 +713,7 @@
// Read it as if we'd seen input with no data (i.e. create a "default" message).
if (Value == null)
{
- var zeroLengthCtx = new ParseContext(new ReadOnlySequence<byte>(ZeroLengthMessageStreamData));
+ ParseContext.Initialize(new ReadOnlySequence<byte>(ZeroLengthMessageStreamData), out ParseContext zeroLengthCtx);
Value = codec.valueCodec.Read(ref zeroLengthCtx);
}
}
diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
index c1b34ea..8cc3536 100644
--- a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
+++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
@@ -95,7 +95,7 @@
/// <param name="codec">The codec to use in order to read each entry.</param>
public void AddEntriesFrom(CodedInputStream input, FieldCodec<T> codec)
{
- var ctx = new ParseContext(input);
+ ParseContext.Initialize(input, out ParseContext ctx);
try
{
AddEntriesFrom(ref ctx, codec);
diff --git a/csharp/src/Google.Protobuf/ExtensionValue.cs b/csharp/src/Google.Protobuf/ExtensionValue.cs
index 497ae4f..7cd0c55 100644
--- a/csharp/src/Google.Protobuf/ExtensionValue.cs
+++ b/csharp/src/Google.Protobuf/ExtensionValue.cs
@@ -96,7 +96,7 @@
public void MergeFrom(CodedInputStream input)
{
- var ctx = new ParseContext(input);
+ ParseContext.Initialize(input, out ParseContext ctx);
try
{
codec.ValueMerger(ref ctx, ref field);
diff --git a/csharp/src/Google.Protobuf/FieldCodec.cs b/csharp/src/Google.Protobuf/FieldCodec.cs
index 50cf8f3..1a71c5c 100644
--- a/csharp/src/Google.Protobuf/FieldCodec.cs
+++ b/csharp/src/Google.Protobuf/FieldCodec.cs
@@ -844,7 +844,7 @@
/// <returns>The value read from the stream.</returns>
public T Read(CodedInputStream input)
{
- var ctx = new ParseContext(input);
+ ParseContext.Initialize(input, out ParseContext ctx);
try
{
return ValueReader(ref ctx);
diff --git a/csharp/src/Google.Protobuf/MessageExtensions.cs b/csharp/src/Google.Protobuf/MessageExtensions.cs
index 97a58c7..51e4091 100644
--- a/csharp/src/Google.Protobuf/MessageExtensions.cs
+++ b/csharp/src/Google.Protobuf/MessageExtensions.cs
@@ -253,7 +253,7 @@
[SecuritySafeCritical]
internal static void MergeFrom(this IMessage message, ReadOnlySequence<byte> data, bool discardUnknownFields, ExtensionRegistry registry)
{
- var ctx = new ParseContext(data);
+ ParseContext.Initialize(data, out ParseContext ctx);
ctx.DiscardUnknownFields = discardUnknownFields;
ctx.ExtensionRegistry = registry;
ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message);
diff --git a/csharp/src/Google.Protobuf/ParseContext.cs b/csharp/src/Google.Protobuf/ParseContext.cs
index 6c74e73..61af8ea 100644
--- a/csharp/src/Google.Protobuf/ParseContext.cs
+++ b/csharp/src/Google.Protobuf/ParseContext.cs
@@ -58,10 +58,11 @@
internal ReadOnlySpan<byte> buffer;
internal ParserInternalState state;
- internal ParseContext(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void Initialize(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state, out ParseContext ctx)
{
- this.buffer = buffer;
- this.state = state;
+ ctx.buffer = buffer;
+ ctx.state = state;
}
/// <summary>
@@ -69,33 +70,37 @@
/// WARNING: internally this copies the CodedInputStream's state, so after done with the ParseContext,
/// the CodedInputStream's state needs to be updated.
/// </summary>
- internal ParseContext(CodedInputStream input)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void Initialize(CodedInputStream input, out ParseContext ctx)
{
- this.buffer = new ReadOnlySpan<byte>(input.InternalBuffer);
+ ctx.buffer = new ReadOnlySpan<byte>(input.InternalBuffer);
// TODO: ideally we would use a reference to the original state, but that doesn't seem possible
- this.state = input.InternalState; // creates copy of the state
+ ctx.state = input.InternalState; // creates copy of the state
}
- internal ParseContext(ReadOnlySequence<byte> input) : this(input, DefaultRecursionLimit)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void Initialize(ReadOnlySequence<byte> input, out ParseContext ctx)
{
+ Initialize(input, DefaultRecursionLimit, out ctx);
}
- internal ParseContext(ReadOnlySequence<byte> input, int recursionLimit)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void Initialize(ReadOnlySequence<byte> input, int recursionLimit, out ParseContext ctx)
{
- this.buffer = default;
- this.state = default;
- this.state.lastTag = 0;
- this.state.recursionDepth = 0;
- this.state.sizeLimit = DefaultSizeLimit;
- this.state.recursionLimit = recursionLimit;
- this.state.currentLimit = int.MaxValue;
- SegmentedBufferHelper.Initialize(input, out this.state.segmentedBufferHelper, out this.buffer);
- this.state.bufferPos = 0;
- this.state.bufferSize = this.buffer.Length;
- this.state.codedInputStream = null;
+ ctx.buffer = default;
+ ctx.state = default;
+ ctx.state.lastTag = 0;
+ ctx.state.recursionDepth = 0;
+ ctx.state.sizeLimit = DefaultSizeLimit;
+ ctx.state.recursionLimit = recursionLimit;
+ ctx.state.currentLimit = int.MaxValue;
+ SegmentedBufferHelper.Initialize(input, out ctx.state.segmentedBufferHelper, out ctx.buffer);
+ ctx.state.bufferPos = 0;
+ ctx.state.bufferSize = ctx.buffer.Length;
+ ctx.state.codedInputStream = null;
- this.state.DiscardUnknownFields = false;
- this.state.ExtensionRegistry = null;
+ ctx.state.DiscardUnknownFields = false;
+ ctx.state.ExtensionRegistry = null;
}
/// <summary>
diff --git a/csharp/src/Google.Protobuf/UnknownFieldSet.cs b/csharp/src/Google.Protobuf/UnknownFieldSet.cs
index fbdf304..b2f288a 100644
--- a/csharp/src/Google.Protobuf/UnknownFieldSet.cs
+++ b/csharp/src/Google.Protobuf/UnknownFieldSet.cs
@@ -258,7 +258,7 @@
public static UnknownFieldSet MergeFieldFrom(UnknownFieldSet unknownFields,
CodedInputStream input)
{
- var ctx = new ParseContext(input);
+ ParseContext.Initialize(input, out ParseContext ctx);
try
{
return MergeFieldFrom(unknownFields, ref ctx);