The JIT doesn't completely eliminate the bounds checks in either of these functions.
publicstaticshortGetValue(){ReadOnlySpan<byte>span=newbyte[]{0x00,0x00,0x00,0x00,0x00,0x00};returnMemoryMarshal.Cast<byte,short>(span)[1];}publicstaticshortGetValueS(refbytea){ReadOnlySpan<byte>span=MemoryMarshal.CreateReadOnlySpan(refa,6);returnMemoryMarshal.Cast<byte,short>(span)[1];}It's able to recognize that the new span has a known length, but doesn't remove the comparison between constants.
G_M41738_IG01:
sub rsp, 40
nop G_M41738_IG02:
mov eax, 3
cmp eax, 1
jbe SHORT G_M41738_IG05
mov rax, 0xD1FFAB1E
movsx rax, word ptr [rax]
G_M41738_IG03:
add rsp, 40
ret G_M41738_IG04:
call CORINFO_HELP_OVERFLOW
int3 G_M41738_IG05:
call CORINFO_HELP_RNGCHKFAIL
int3 ; Total bytes of code 46
-------------------------------------
G_M41737_IG01:
sub rsp, 40
nop G_M41737_IG02:
mov eax, 3
cmp eax, 1
jbe SHORT G_M41737_IG05
movsx rax, word ptr [rcx+2]
G_M41737_IG03:
add rsp, 40
ret G_M41737_IG04:
call CORINFO_HELP_OVERFLOW
int3 G_M41737_IG05:
call CORINFO_HELP_RNGCHKFAIL
int3 ; Total bytes of code 37
Returning a byte instead of casting to a short results in no bounds checks.
G_M41729_IG01:
nop G_M41729_IG02:
mov rax, 0xD1FFAB1E
movzx rax, byte ptr [rax]
G_M41729_IG03:
ret ; Total bytes of code 19
-------------------------------------
G_M41728_IG01:
nop G_M41728_IG02:
movzx rax, byte ptr [rcx+1]
G_M41728_IG03:
ret ; Total bytes of code 10
category:cq
theme:bounds-checks
skill-level:expert
cost:medium
The JIT doesn't completely eliminate the bounds checks in either of these functions.
It's able to recognize that the new span has a known length, but doesn't remove the comparison between constants.
Returning a byte instead of casting to a short results in no bounds checks.
category:cq
theme:bounds-checks
skill-level:expert
cost:medium