Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Commit 89e8f72

Browse files
committed
Reduce GetString allocs and conversions
1 parent facf3ad commit 89e8f72

File tree

3 files changed

+84
-11
lines changed

3 files changed

+84
-11
lines changed

src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ private bool TakeStartLine(SocketInput input)
627627
{
628628
return false;
629629
}
630-
var method = begin.GetString(scan);
630+
var method = begin.GetAsciiString(scan);
631631

632632
scan.Take();
633633
begin = scan;
@@ -651,7 +651,7 @@ private bool TakeStartLine(SocketInput input)
651651
{
652652
return false;
653653
}
654-
queryString = begin.GetString(scan);
654+
queryString = begin.GetAsciiString(scan);
655655
}
656656

657657
scan.Take();
@@ -660,20 +660,24 @@ private bool TakeStartLine(SocketInput input)
660660
{
661661
return false;
662662
}
663-
var httpVersion = begin.GetString(scan);
663+
var httpVersion = begin.GetAsciiString(scan);
664664

665665
scan.Take();
666666
if (scan.Take() != '\n')
667667
{
668668
return false;
669669
}
670670

671+
string requestUrlPath;
671672
if (needDecode)
672673
{
673674
pathEnd = UrlPathDecoder.Unescape(pathBegin, pathEnd);
675+
requestUrlPath = pathBegin.GetUtf8String(pathEnd);
676+
}
677+
else
678+
{
679+
requestUrlPath = pathBegin.GetAsciiString(pathEnd);
674680
}
675-
676-
var requestUrlPath = pathBegin.GetString(pathEnd);
677681

678682
consumed = scan;
679683
Method = method;
@@ -785,7 +789,7 @@ public static bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders req
785789
}
786790

787791
var name = beginName.GetArraySegment(endName);
788-
var value = beginValue.GetString(endValue);
792+
var value = beginValue.GetAsciiString(endValue);
789793
if (wrapping)
790794
{
791795
value = value.Replace("\r\n", " ");

src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,76 @@ public int GetLength(MemoryPoolIterator2 end)
488488
}
489489
}
490490

491-
public string GetString(MemoryPoolIterator2 end)
491+
private static unsafe string SingleBlockAsciiString(byte[] input, int offset, int length)
492+
{
493+
// avoid declaring other local vars, or doing work with stackalloc
494+
// to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
495+
char* output = stackalloc char[length];
496+
497+
return SingleBlockAsciiIter(output, input, offset, length);
498+
}
499+
500+
private static unsafe string SingleBlockAsciiIter(char* output, byte[] input, int offset, int length)
501+
{
502+
// avoid declaring other local vars, or doing work with stackalloc
503+
// to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
504+
for (var i = 0; i < length; i++)
505+
{
506+
output[i] = (char)input[i + offset];
507+
}
508+
return new string(output, 0, length);
509+
}
510+
511+
private static unsafe string MultiBlockAsciiString(MemoryPoolBlock2 block, int offset, int length)
512+
{
513+
// avoid declaring other local vars, or doing work with stackalloc
514+
// to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
515+
char* output = stackalloc char[length];
516+
517+
return MultiBlockAsciiIter(output, block, offset, length);
518+
}
519+
520+
private static unsafe string MultiBlockAsciiIter(char* output, MemoryPoolBlock2 block, int offset, int length)
521+
{
522+
// avoid declaring other local vars, or doing work with stackalloc
523+
// to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
524+
while (length > 0)
525+
{
526+
var following = block.End - offset;
527+
var input = block.Array;
528+
529+
for (var i = 0; i < following; i++)
530+
{
531+
output[i] = (char)input[i + offset];
532+
}
533+
534+
length -= following;
535+
536+
block = block.Next;
537+
offset = block.Start;
538+
}
539+
540+
return new string(output, 0, length);
541+
}
542+
543+
public string GetAsciiString(MemoryPoolIterator2 end)
544+
{
545+
// avoid declaring other local vars, or doing work with stackalloc
546+
// to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
547+
if (IsDefault || end.IsDefault)
548+
{
549+
return default(string);
550+
}
551+
552+
if (end._block == _block)
553+
{
554+
return SingleBlockAsciiString(_block.Array, _index, end._index - _index);
555+
}
556+
557+
return MultiBlockAsciiString(_block, _index, GetLength(end));
558+
}
559+
560+
public string GetUtf8String(MemoryPoolIterator2 end)
492561
{
493562
if (IsDefault || end.IsDefault)
494563
{

test/Microsoft.AspNet.Server.KestrelTests/UrlPathDecoder.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public void DecodeWithBoundary(string raw, int rawLength, string expect, int exp
115115
var end = GetIterator(begin, rawLength);
116116

117117
var end2 = UrlPathDecoder.Unescape(begin, end);
118-
var result = begin.GetString(end2);
118+
var result = begin.GetUtf8String(end2);
119119

120120
Assert.Equal(expectLength, result.Length);
121121
Assert.Equal(expect, result);
@@ -147,7 +147,7 @@ private void PositiveAssert(string raw, string expect)
147147
var end = GetIterator(begin, raw.Length);
148148

149149
var result = UrlPathDecoder.Unescape(begin, end);
150-
Assert.Equal(expect, begin.GetString(result));
150+
Assert.Equal(expect, begin.GetUtf8String(result));
151151
}
152152

153153
private void PositiveAssert(string raw)
@@ -156,7 +156,7 @@ private void PositiveAssert(string raw)
156156
var end = GetIterator(begin, raw.Length);
157157

158158
var result = UrlPathDecoder.Unescape(begin, end);
159-
Assert.NotEqual(raw.Length, begin.GetString(result).Length);
159+
Assert.NotEqual(raw.Length, begin.GetUtf8String(result).Length);
160160
}
161161

162162
private void NegativeAssert(string raw)
@@ -165,7 +165,7 @@ private void NegativeAssert(string raw)
165165
var end = GetIterator(begin, raw.Length);
166166

167167
var resultEnd = UrlPathDecoder.Unescape(begin, end);
168-
var result = begin.GetString(resultEnd);
168+
var result = begin.GetUtf8String(resultEnd);
169169
Assert.Equal(raw, result);
170170
}
171171
}

0 commit comments

Comments
 (0)