From ecc96e76c51ca55ff885e08aefb5d7cbdeed36a5 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Tue, 5 Feb 2019 05:04:30 +0100 Subject: [PATCH] Fix string.strlen (dotnet/coreclr#22397) * Add explanation comment Fixes #22393 Signed-off-by: dotnet-bot --- .../shared/System/SpanHelpers.Byte.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs b/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs index 443c7bed9e7..9672f343ebc 100644 --- a/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs +++ b/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs @@ -266,10 +266,36 @@ public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) offset += 1; } + // We get past SequentialScan only if IsHardwareAccelerated or intrinsic .IsSupported is true; and remain length is greater than Vector length. + // However, we still have the redundant check to allow the JIT to see that the code is unreachable and eliminate it when the platform does not + // have hardware accelerated. After processing Vector lengths we return to SequentialScan to finish any remaining. if (Avx2.IsSupported) { if ((int)(byte*)offset < length) { + if ((((nuint)Unsafe.AsPointer(ref searchSpace) + (nuint)offset) & (nuint)(Vector256.Count - 1)) != 0) + { + // Not currently aligned to Vector256 (is aligned to Vector128); this can cause a problem for searches + // with no upper bound e.g. String.strlen. + // Start with a check on Vector128 to align to Vector256, before moving to processing Vector256. + // This ensures we do not fault across memory pages while searching for an end of string. + Vector128 values = Vector128.Create(value); + Vector128 search = LoadVector128(ref searchSpace, offset); + + // Same method as below + int matches = Sse2.MoveMask(Sse2.CompareEqual(values, search)); + if (matches == 0) + { + // Zero flags set so no matches + offset += Vector128.Count; + } + else + { + // Find bitflag offset of first match and add to current offset + return ((int)(byte*)offset) + BitOps.TrailingZeroCount(matches); + } + } + nLength = GetByteVector256SpanLength(offset, length); if ((byte*)nLength > (byte*)offset) {