-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
I see it's quite common for CoreCLR/FX to have quite big static readonly arrays of bytes. e.g.
Char.cs#L41-L74
ParserHelpers.cs#L29-L47
Rune.cs#L32-L42
RegexParser.cs#L1969-L1977
CaseInsensitiveAscii.cs#L13-L40
so I wonder if such a table has 256 elements and we try to access it via a byte indexer we will never go out of bounds, e.g.:
static ReadOnlySpan<byte> s_hexDecodeMap => new byte[]
//static readonly byte[] s_hexDecodeMap = new byte[]
{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 0
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 1
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 2
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, // 3
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 4
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 5
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 6
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 7
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 8
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 9
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // A
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // B
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // C
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // D
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // E
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // F
}; // 256 elements
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
static byte GetByte(byte index)
{
return s_hexDecodeMap[index];
}Currently generates:
; Method Tests:GetByte(ubyte):ubyte
G_M45444_IG01:
sub rsp, 40
G_M45444_IG02:
movzx rax, cl
cmp eax, 256 // redundant
jae SHORT G_M45444_IG04 // redundant
movsxd rax, eax
mov rdx, 0xD1FFAB1E
movzx rax, byte ptr [rax+rdx]
G_M45444_IG03:
add rsp, 40
ret
G_M45444_IG04: // redundant
call CORINFO_HELP_RNGCHKFAIL // redundant
int3 // redundant
; Total bytes of code: 42So we don't need bound checks here since index simply can't be >256. Also if a byte map, let's say, has 100-200 elements I guess we can extend it to be 256 bytes (a small memory regression - faster access, no branching). It can be important when you port some performance-critical code/libraries from C++ to C# e.g. https://godbolt.org/z/7kVk_5
category:cq
theme:range-check
skill-level:beginner
cost:small