Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Fast-path for ASCII & UTF8 Encoding ASCII data #8969

Merged
merged 8 commits into from
Jan 24, 2017

Conversation

benaadams
Copy link
Member

@benaadams benaadams commented Jan 17, 2017

Up to x4 faster on Encoding.GetBytes(String s) for UTF8 and ASCII when string is ascii.

Have #if !BIGENDIAN the changes as don't have have a good way of confirming the pattern for little endian.

Call chains changed mostly to Virtual call->validate->concrete call; previously it would do virtual call chains with validations on each call.

The string overload has a wrinkle. It will optimistically take string.length as the length of they output bytes; if it encounters a non-ascii char it will then count from that point forward, reallocate the array and copy the bytes to the correct sized array; then pass over to the current implementation to complete - so you maybe get double byte[] allocations. The array versions don't exhibit this behaviour.

Following up on https://github.com/dotnet/coreclr/issues/6759 /cc @jamesqo

@benaadams
Copy link
Member Author

benaadams commented Jan 17, 2017

Encoding.GetBytes(String s) PerfTesting/AsciiEncoding

           Method | StringLength |          Mean | Scaled |            RPS | Allocated |
----------------- |------------- |-------------- |------- |--------------- |---------- |
    ASCIIGetBytes |            0 |    38.4659 ns |   1.00 |  25,997,064.34 |      55 B |
     UTF8GetBytes |            0 |    34.0826 ns |   0.89 |  29,340,494.77 |      55 B |
 FastPathGetBytes |            0 |     4.3241 ns |   0.11 | 231,260,406.01 |       0 B |
    ASCIIGetBytes |            1 |    35.0843 ns |   1.00 |  28,502,794.72 |      31 B |
     UTF8GetBytes |            1 |    40.7989 ns |   1.16 |  24,510,487.01 |      31 B |
 FastPathGetBytes |            1 |    15.8264 ns |   0.45 |  63,185,503.90 |      31 B |
    ASCIIGetBytes |            2 |    36.7773 ns |   1.00 |  27,190,672.96 |      31 B |
     UTF8GetBytes |            2 |    41.4267 ns |   1.13 |  24,139,002.87 |      31 B |
 FastPathGetBytes |            2 |    17.1762 ns |   0.47 |  58,220,043.08 |      31 B |
    ASCIIGetBytes |            3 |    38.5192 ns |   1.00 |  25,961,074.16 |      31 B |
     UTF8GetBytes |            3 |    44.7293 ns |   1.16 |  22,356,720.37 |      31 B |
 FastPathGetBytes |            3 |    18.0674 ns |   0.47 |  55,348,347.42 |      31 B |
    ASCIIGetBytes |            4 |    40.2293 ns |   1.00 |  24,857,521.12 |      31 B |
     UTF8GetBytes |            4 |    47.8462 ns |   1.19 |  20,900,283.19 |      31 B |
 FastPathGetBytes |            4 |    19.1069 ns |   0.47 |  52,336,994.78 |      31 B |
    ASCIIGetBytes |            5 |    41.9509 ns |   1.00 |  23,837,393.88 |      31 B |
     UTF8GetBytes |            5 |    50.4886 ns |   1.20 |  19,806,446.68 |      31 B |
 FastPathGetBytes |            5 |    19.6285 ns |   0.47 |  50,946,272.29 |      31 B |
    ASCIIGetBytes |            6 |    43.4820 ns |   1.00 |  22,998,030.98 |      31 B |
     UTF8GetBytes |            6 |    52.6119 ns |   1.21 |  19,007,105.66 |      31 B |
 FastPathGetBytes |            6 |    20.4859 ns |   0.47 |  48,814,092.96 |      31 B |
    ASCIIGetBytes |            7 |    45.2872 ns |   1.00 |  22,081,314.12 |      31 B |
     UTF8GetBytes |            7 |    55.0579 ns |   1.22 |  18,162,695.92 |      31 B |
 FastPathGetBytes |            7 |    17.9490 ns |   0.40 |  55,713,395.49 |      31 B |
    ASCIIGetBytes |            8 |    46.9418 ns |   1.00 |  21,302,959.11 |      31 B |
     UTF8GetBytes |            8 |    56.8499 ns |   1.21 |  17,590,186.79 |      31 B |
 FastPathGetBytes |            8 |    18.9719 ns |   0.40 |  52,709,606.78 |      31 B |
    ASCIIGetBytes |           14 |    57.8146 ns |   1.00 |  17,296,670.28 |      39 B |
     UTF8GetBytes |           14 |    74.9049 ns |   1.30 |  13,350,266.65 |      39 B |
 FastPathGetBytes |           14 |    22.5186 ns |   0.39 |  44,407,706.50 |      39 B |
    ASCIIGetBytes |           15 |    59.9135 ns |   1.00 |  16,690,738.98 |      39 B |
     UTF8GetBytes |           15 |    73.0695 ns |   1.22 |  13,685,593.50 |      39 B |
 FastPathGetBytes |           15 |    20.7145 ns |   0.35 |  48,275,309.41 |      39 B |
    ASCIIGetBytes |           16 |    70.1182 ns |   1.00 |  14,261,634.50 |      39 B |
     UTF8GetBytes |           16 |    68.8123 ns |   0.98 |  14,532,275.71 |      39 B |
 FastPathGetBytes |           16 |    21.4978 ns |   0.31 |  46,516,364.33 |      39 B |
    ASCIIGetBytes |           17 |    70.3667 ns |   1.00 |  14,211,261.96 |      47 B |
     UTF8GetBytes |           17 |    73.4145 ns |   1.04 |  13,621,287.74 |      47 B |
 FastPathGetBytes |           17 |    22.9815 ns |   0.33 |  43,513,273.40 |      47 B |
    ASCIIGetBytes |           18 |    74.8212 ns |   1.00 |  13,365,197.96 |      47 B |
     UTF8GetBytes |           18 |    69.5903 ns |   0.93 |  14,369,816.97 |      47 B |
 FastPathGetBytes |           18 |    21.8974 ns |   0.29 |  45,667,563.71 |      47 B |
    ASCIIGetBytes |           32 |   101.3085 ns |   1.00 |   9,870,836.34 |      55 B |
     UTF8GetBytes |           32 |    81.2491 ns |   0.80 |  12,307,823.71 |      55 B |
 FastPathGetBytes |           32 |    27.4950 ns |   0.27 |  36,370,249.41 |      55 B |
    ASCIIGetBytes |           63 |   161.0612 ns |   1.00 |   6,208,819.98 |      87 B |
     UTF8GetBytes |           63 |   116.8431 ns |   0.73 |   8,558,487.07 |      87 B |
 FastPathGetBytes |           63 |    39.1155 ns |   0.24 |  25,565,311.21 |      87 B |
    ASCIIGetBytes |           64 |   163.9895 ns |   1.00 |   6,097,951.76 |      87 B |
     UTF8GetBytes |           64 |   116.5886 ns |   0.71 |   8,577,166.78 |      87 B |
 FastPathGetBytes |           64 |    40.2730 ns |   0.25 |  24,830,551.60 |      87 B |
    ASCIIGetBytes |           65 |   166.8880 ns |   1.00 |   5,992,043.51 |      95 B |
     UTF8GetBytes |           65 |   119.6743 ns |   0.72 |   8,356,013.05 |      95 B |
 FastPathGetBytes |           65 |    40.9087 ns |   0.25 |  24,444,675.47 |      95 B |
    ASCIIGetBytes |          128 |   285.9522 ns |   1.00 |   3,497,088.31 |     151 B |
     UTF8GetBytes |          128 |   209.3091 ns |   0.73 |   4,777,622.91 |     151 B |
 FastPathGetBytes |          128 |    66.6881 ns |   0.23 |  14,995,185.02 |     151 B |
    ASCIIGetBytes |          256 |   531.6415 ns |   1.00 |   1,880,966.89 |     279 B |
     UTF8GetBytes |          256 |   386.5149 ns |   0.73 |   2,587,222.60 |     279 B |
 FastPathGetBytes |          256 |   121.0964 ns |   0.23 |   8,257,883.59 |     279 B |
    ASCIIGetBytes |          512 | 1,025.1415 ns |   1.00 |     975,475.11 |     534 B |
     UTF8GetBytes |          512 |   707.9482 ns |   0.69 |   1,412,532.72 |     534 B |
 FastPathGetBytes |          512 |   240.9107 ns |   0.24 |   4,150,914.96 |     534 B |
    ASCIIGetBytes |         1024 | 2,036.6071 ns |   1.00 |     491,012.73 |   1.04 kB |
     UTF8GetBytes |         1024 | 1,349.8871 ns |   0.66 |     740,802.70 |   1.04 kB |
 FastPathGetBytes |         1024 |   465.0265 ns |   0.23 |   2,150,415.03 |   1.04 kB |

@jkotas
Copy link
Member

jkotas commented Jan 17, 2017

cc @KrzysztofCwalina


int lengthEncoded;
if ((encoder?.InternalHasFallbackBuffer ?? false) &&
(encoder.FallbackBuffer.InternalGetNextChar()) != 0) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the correct test to check if the ASCII and UTF8 EncoderNLS encoder has a char in their buffer from a previous call?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be
encoder.FallbackBuffer.Remaining > 0


In reply to: 96473296 [](ancestors = 96473296)

@KrzysztofCwalina
Copy link
Member

cc: @shiftylogic, @ahsonkhan

@danmoseley
Copy link
Member

@safern

@benaadams
Copy link
Member Author

@dotnet-bot retest Linux ARM Emulator Cross Debug Build

@benaadams
Copy link
Member Author

The non-allocating method GetBytes(String s, int charIndex, int charCount, byte[] bytes, int byteIndex) improves up to x5 for ascii and x1.5 for utf8

           Method | ArrayLength |          Mean | Scaled |           RPS |
----------------- |------------ |-------------- |------- |-------------- |
    ASCIIGetBytes |           1 |    19.6575 ns |   1.00 | 50,871,237.55 |
     UTF8GetBytes |           1 |    21.0086 ns |   1.07 | 47,599,605.12 |
 FastPathGetBytes |           1 |    12.7490 ns |   0.65 | 78,437,453.42 |
    ASCIIGetBytes |          16 |    53.5428 ns |   1.00 | 18,676,658.18 |
     UTF8GetBytes |          16 |    33.7164 ns |   0.63 | 29,659,119.93 |
 FastPathGetBytes |          16 |    18.2202 ns |   0.34 | 54,884,141.22 |
    ASCIIGetBytes |          64 |   140.8655 ns |   1.00 |  7,098,968.50 |
     UTF8GetBytes |          64 |    56.9533 ns |   0.40 | 17,558,259.90 |
 FastPathGetBytes |          64 |    32.5284 ns |   0.23 | 30,742,390.79 |
    ASCIIGetBytes |         125 |   252.9913 ns |   1.00 |  3,952,705.11 |
     UTF8GetBytes |         125 |    93.3715 ns |   0.37 | 10,709,911.02 |
 FastPathGetBytes |         125 |    53.7295 ns |   0.21 | 18,611,746.81 |
    ASCIIGetBytes |         250 |   493.5918 ns |   1.00 |  2,025,965.40 |
     UTF8GetBytes |         250 |   182.9843 ns |   0.37 |  5,464,949.17 |
 FastPathGetBytes |         250 |   106.7233 ns |   0.22 |  9,370,027.53 |
    ASCIIGetBytes |         500 |   956.8627 ns |   1.00 |  1,045,081.99 |
     UTF8GetBytes |         500 |   329.6892 ns |   0.34 |  3,033,159.80 |
 FastPathGetBytes |         500 |   195.6080 ns |   0.20 |  5,112,264.73 |
    ASCIIGetBytes |        1000 | 1,900.0187 ns |   1.00 |    526,310.61 |
     UTF8GetBytes |        1000 |   617.5636 ns |   0.33 |  1,619,266.39 |
 FastPathGetBytes |        1000 |   370.6225 ns |   0.20 |  2,698,163.22 |
    ASCIIGetBytes |        2000 | 3,781.9515 ns |   1.00 |    264,413.76 |
     UTF8GetBytes |        2000 | 1,202.1412 ns |   0.32 |    831,849.04 |
 FastPathGetBytes |        2000 |   722.5315 ns |   0.19 |  1,384,022.67 |
    ASCIIGetBytes |        4000 | 7,594.2975 ns |   1.00 |    131,677.75 |
     UTF8GetBytes |        4000 | 2,360.3888 ns |   0.31 |    423,659.01 |
 FastPathGetBytes |        4000 | 1,428.4707 ns |   0.19 |    700,049.36 |

@benaadams
Copy link
Member Author

benaadams commented Jan 18, 2017

Worse-case regression from complete fallback (though the perf test does double validation for Fastpath and coreclr version doesn't)

                Method | ArrayLength |          Mean | Scaled |           RPS |
---------------------- |------------ |-------------- |------- |-------------- |
         ASCIIGetBytes |           2 |    21.8932 ns |   1.00 | 45,676,241.14 |
 FastPathASCIIGetBytes |           2 |    28.0950 ns |   1.28 | 35,593,515.53 |
          UTF8GetBytes |           2 |    28.6037 ns |   1.31 | 34,960,480.71 |
  FastPathUTF8GetBytes |           2 |    33.9756 ns |   1.55 | 29,432,930.09 |
         ASCIIGetBytes |          16 |    49.5413 ns |   1.00 | 20,185,162.35 |
 FastPathASCIIGetBytes |          16 |    56.0409 ns |   1.13 | 17,844,107.19 |
          UTF8GetBytes |          16 |    99.6528 ns |   2.01 | 10,034,840.62 |
  FastPathUTF8GetBytes |          16 |   105.3579 ns |   2.13 |  9,491,457.00 |
         ASCIIGetBytes |          64 |   142.5079 ns |   1.00 |  7,017,157.03 |
 FastPathASCIIGetBytes |          64 |   159.2888 ns |   1.12 |  6,277,907.24 |
          UTF8GetBytes |          64 |   234.4658 ns |   1.65 |  4,265,014.77 |
  FastPathUTF8GetBytes |          64 |   239.0019 ns |   1.68 |  4,184,067.40 |
         ASCIIGetBytes |         128 |   255.3577 ns |   1.00 |  3,916,075.06 |
 FastPathASCIIGetBytes |         128 |   274.1093 ns |   1.07 |  3,648,180.37 |
          UTF8GetBytes |         128 |   383.0374 ns |   1.50 |  2,610,710.98 |
  FastPathUTF8GetBytes |         128 |   389.9771 ns |   1.53 |  2,564,253.12 |
         ASCIIGetBytes |         250 |   481.6879 ns |   1.00 |  2,076,033.23 |
 FastPathASCIIGetBytes |         250 |   555.6237 ns |   1.16 |  1,799,779.37 |
          UTF8GetBytes |         250 |   656.3861 ns |   1.36 |  1,523,493.46 |
  FastPathUTF8GetBytes |         250 |   661.1593 ns |   1.37 |  1,512,494.73 |
         ASCIIGetBytes |         500 |   914.2467 ns |   1.00 |  1,093,796.67 |
 FastPathASCIIGetBytes |         500 | 1,038.8412 ns |   1.14 |    962,611.03 |
          UTF8GetBytes |         500 | 1,185.9378 ns |   1.30 |    843,214.55 |
  FastPathUTF8GetBytes |         500 | 1,192.9804 ns |   1.30 |    838,236.71 |
         ASCIIGetBytes |        1000 | 1,806.5485 ns |   1.00 |    553,541.74 |
 FastPathASCIIGetBytes |        1000 | 1,983.1114 ns |   1.10 |    504,258.11 |
          UTF8GetBytes |        1000 | 2,241.0633 ns |   1.24 |    446,216.76 |
  FastPathUTF8GetBytes |        1000 | 2,250.3882 ns |   1.25 |    444,367.78 |
         ASCIIGetBytes |        2000 | 3,572.5739 ns |   1.00 |    279,910.23 |
 FastPathASCIIGetBytes |        2000 | 3,871.9489 ns |   1.08 |    258,267.87 |
          UTF8GetBytes |        2000 | 4,345.5549 ns |   1.22 |    230,120.21 |
  FastPathUTF8GetBytes |        2000 | 4,354.2565 ns |   1.22 |    229,660.33 |
         ASCIIGetBytes |        4000 | 7,052.4148 ns |   1.00 |    141,795.40 |
 FastPathASCIIGetBytes |        4000 | 7,688.7309 ns |   1.09 |    130,060.48 |
          UTF8GetBytes |        4000 | 8,543.7092 ns |   1.21 |    117,045.18 |
  FastPathUTF8GetBytes |        4000 | 8,539.5632 ns |   1.21 |    117,102.01 |

Isn't too significant? (as ascii is a very common path for high thoughput data e.g. json, html, xml, web apis; data based files etc)

@danmoseley
Copy link
Member

@tarekgh or @krwq could you take a look? interestingly this codepath is showing up on some of our TechEmpower traces. it will be interesting to retest with this change.

@tarekgh
Copy link
Member

tarekgh commented Jan 23, 2017

Will take a look today.

@@ -12,6 +12,10 @@ namespace System.Text

internal static class EncodingForwarder
{
#if !BIGENDIAN
const int Shift16Shift24 = 256 * 256 * 256 + 256 * 256;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: (1 << 16) | (1 << 24) seems less magic, less error prone and more obvious when looking at both name and value

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed, also moved const into function

@@ -12,6 +12,10 @@ namespace System.Text

internal static class EncodingForwarder
{
#if !BIGENDIAN
const int Shift16Shift24 = 256 * 256 * 256 + 256 * 256;
const int Shift8Identity = 256 + 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed, also moved const into function

public override byte[] GetBytes(String s)
=> EncodingForwarder.GetBytesAsciiFastPath(this, s);

public override int GetBytes(String s, int charIndex, int charCount, byte[] bytes, int byteIndex)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String s [](start = 37, length = 8)

please keep the original paramter names . like in this case it should be "String chars"

@@ -281,7 +302,7 @@ internal override unsafe int GetByteCount(char* chars, int charCount, EncoderNLS
return byteCount;
}

internal override unsafe int GetBytes(char* chars, int charCount,
internal override unsafe int GetBytesFallback(char* chars, int charCount,
Copy link
Member

@tarekgh tarekgh Jan 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this change will cause the code compiled with BIGENDIAN to have stackoverflow (recursive calls).

public override int GetBytes(String chars, int charIndex, int charCount,byte[] bytes, int byteIndex) calls
EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex); which will call
encoding.GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, encoder: null);

because you have renamed it here, the base encoding (Encoding class) version will get called which is
Encoding.GetBytes(char* chars, int charCount, byte* bytes, int byteCount, EncoderNLS encoder) which calls
ASCIIEncoding.GetBytes(char* chars, int charCount, byte* bytes, int byteCount) which calls
EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex);

and we'll loop forever

byte[] bytes, int byteIndex)
{
return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex);
#if !BIGENDIAN
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is acceptable for now to have the ifdef as we have other code placed under same ifdef too.
@jkotas what you think of changing this to runtime check instead of compile time check? I mean we can detect if we are running on BIGENDIA.

Copy link
Member

@jkotas jkotas Jan 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CoreLib is build architecture specific for number of different reasons. If you would like the code to be more pretty (and create more work for JIT to get rid of unreachable code), you can do the check dynamically based on a static property and have the property return true/false constant under ifdef.

@@ -580,7 +601,7 @@ private static bool InRange(int ch, int start, int end)

// Our workhorse
// Note: We ignore mismatched surrogates, unless the exception flag is set in which case we throw
internal override unsafe int GetBytes(char* chars, int charCount,
internal override unsafe int GetBytesFallback(char* chars, int charCount,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same previous comment

@tarekgh
Copy link
Member

tarekgh commented Jan 24, 2017

        return m_encoding.GetByteCount(chars, count, this);

it would be better to move these lines to its own helper method and have both overloads of GetByteCount to call this helper instead of duplicating the code. the reason is if we need to do more changes in the future we'll have one place to change


Refers to: src/mscorlib/src/System/Text/EncoderNLS.cs:118 in 1b8a70c. [](commit_id = 1b8a70c, deletion_comment = False)

@tarekgh
Copy link
Member

tarekgh commented Jan 24, 2017

        return m_encoding.GetBytes(chars, charCount, bytes, byteCount, this);

ditto


Refers to: src/mscorlib/src/System/Text/EncoderNLS.cs:174 in 1b8a70c. [](commit_id = 1b8a70c, deletion_comment = False)

@tarekgh
Copy link
Member

tarekgh commented Jan 24, 2017

ditto


Refers to: src/mscorlib/src/System/Text/EncoderNLS.cs:258 in 1b8a70c. [](commit_id = 1b8a70c, deletion_comment = False)

byte[] bytes;
fixed (char* pChar = s) {
int byteCount = GetByteCount(pChar + index, count);
if (byteCount == 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (byteCount == 0) { [](start = 15, length = 22)

please try to use the coding style

if ()
{
}
else
{
}

I know the old code was not doing that but any changed code we should use the right style

{
int byteCount = GetByteCount(pChar + index, count);
if (byteCount == 0)
return Array.Empty<byte>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: why not keeping this logic? I mean just return when byteCount is zero. that will make the code readability better (I guess)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoiding an inline return in fixed block.

However I was wondering about this; if count > 0 could byteCount ever be zero? If not the test and return could be done before either the fixed or call to GetByteCount. Was assuming an edge case I hadn't considered...

Copy link
Member Author

@benaadams benaadams Jan 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe BOM, or encoder always outputting something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is wrong if you return from the fixed block?

for returning 0 byte count, I believe this can happen if we have custom encoder who can fallback and will have a state after finishing.


In reply to: 97555441 [](ancestors = 97555441)

int charCount = s.Length;

byte[] bytes;
if (charCount > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use the right coding style. thanks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that my comment apply in different places so I'll not repeat the comment again assuming you'll fix all touched places.


In reply to: 97451474 [](ancestors = 97451474)

char* input = pInput + charIndex;
byte* output = pOutput + byteIndex;
lengthEncoded = GetBytesAsciiFastPath(input, output, Math.Min(charCount, byteCount));
if (lengthEncoded < byteCount) {
Copy link
Member

@tarekgh tarekgh Jan 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we check if lengthEncoded is >= charCount and then exit? your check here can cause calling encoding.GetBytesFallback while is not needed (like in cases having pure ascii string and calling with big value of byteCount)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be testing against the Mind length in all cases? e.g. Math.Min(charCount, byteCount) will add var and change

ThrowBytesOverflow(encoding);

int lengthEncoded;
if (charCount > 0 && byteCount > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

      if (charCount > 0 && byteCount > 0) { [](start = 1, length = 48)

same as previous comment

}
else if (charCount > 0 && byteCount > 0) {
lengthEncoded = GetBytesAsciiFastPath(chars, bytes, Math.Min(charCount, byteCount));
if (lengthEncoded < charCount) {
Copy link
Member

@tarekgh tarekgh Jan 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto. I'll not comment again on the same issue in the rest of the changes

#if BIT64
if (byteCount < 4) goto trailing;

int unaligned = (unchecked(-(int)input) >> 1) & 0x3;
Copy link
Member

@tarekgh tarekgh Jan 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int unaligned = (unchecked(-(int)input) >> 1) & 0x3; [](start = 11, length = 53)

would it be clearer if we write this as
int unaligned = (((ulong)input) & 0x7) >> 1;

@tarekgh
Copy link
Member

tarekgh commented Jan 24, 2017

@benaadams thanks a lot for your effort and getting this done. LGTM

@benaadams
Copy link
Member Author

Just want to factor out a couple throw blocks

@tarekgh
Copy link
Member

tarekgh commented Jan 24, 2017

Just want to factor out a couple throw blocks

you mean you are going to push one more commit? I'll wait for that before merging then.

@benaadams
Copy link
Member Author

@tarekgh added, also added for other function that had all the vars to check

@tarekgh
Copy link
Member

tarekgh commented Jan 24, 2017

@benaadams thanks again.

@tarekgh tarekgh merged commit 5c20488 into dotnet:master Jan 24, 2017
@karelz karelz modified the milestone: 2.0.0 Aug 28, 2017
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
* ASCII Encoding fast-path

* Add skipp for BIGENDIAN

* fixes

* ascii  GetBytes(char[] chars) fix

* feedback

* Clean up

* Reuse exception block

* Add debug Asserts


Commit migrated from dotnet/coreclr@5c20488
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants