ソースを参照

optimize initialization of ParseContext

Jan Tattermusch 5 年 前
コミット
07182a843c

+ 1 - 1
csharp/src/Google.Protobuf.Benchmarks/ParseMessagesBenchmark.cs

@@ -195,7 +195,7 @@ namespace Google.Protobuf.Benchmarks
 
             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();

+ 8 - 8
csharp/src/Google.Protobuf.Benchmarks/ParseRawPrimitivesBenchmark.cs

@@ -105,7 +105,7 @@ namespace Google.Protobuf.Benchmarks
         [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 @@ namespace Google.Protobuf.Benchmarks
         [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 @@ namespace Google.Protobuf.Benchmarks
         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 @@ namespace Google.Protobuf.Benchmarks
         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 @@ namespace Google.Protobuf.Benchmarks
         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 @@ namespace Google.Protobuf.Benchmarks
         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 @@ namespace Google.Protobuf.Benchmarks
             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)

+ 3 - 3
csharp/src/Google.Protobuf/CodedInputStream.cs

@@ -431,7 +431,7 @@ namespace Google.Protobuf
         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 @@ namespace Google.Protobuf
         /// </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 @@ namespace Google.Protobuf
         /// </summary>
         public void ReadRawMessage(IMessage message)
         {
-            var ctx = new ParseContext(this);
+            ParseContext.Initialize(this, out ParseContext ctx);
             try
             {
                 ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message);

+ 1 - 1
csharp/src/Google.Protobuf/Collections/MapField.cs

@@ -713,7 +713,7 @@ namespace Google.Protobuf.Collections
                     // 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);
                     }
                 }

+ 1 - 1
csharp/src/Google.Protobuf/Collections/RepeatedField.cs

@@ -95,7 +95,7 @@ namespace Google.Protobuf.Collections
         /// <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);

+ 1 - 1
csharp/src/Google.Protobuf/ExtensionValue.cs

@@ -96,7 +96,7 @@ namespace Google.Protobuf
 
         public void MergeFrom(CodedInputStream input)
         {
-            var ctx = new ParseContext(input);
+            ParseContext.Initialize(input, out ParseContext ctx);
             try
             {
                 codec.ValueMerger(ref ctx, ref field);

+ 1 - 1
csharp/src/Google.Protobuf/FieldCodec.cs

@@ -844,7 +844,7 @@ namespace Google.Protobuf
         /// <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);

+ 1 - 1
csharp/src/Google.Protobuf/MessageExtensions.cs

@@ -253,7 +253,7 @@ namespace Google.Protobuf
         [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);

+ 27 - 22
csharp/src/Google.Protobuf/ParseContext.cs

@@ -58,10 +58,11 @@ namespace Google.Protobuf
         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 @@ namespace Google.Protobuf
         /// 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;
-
-            this.state.DiscardUnknownFields = false;
-            this.state.ExtensionRegistry = 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;
+
+            ctx.state.DiscardUnknownFields = false;
+            ctx.state.ExtensionRegistry = null;
         }
 
         /// <summary>

+ 1 - 1
csharp/src/Google.Protobuf/UnknownFieldSet.cs

@@ -258,7 +258,7 @@ namespace Google.Protobuf
         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);