-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Description
The JIT doesn't generate good assembly when calculating (what should be) constant fields offsets.
Example sharplab
Configuration
.NET 5, master branch on sharplab and I repro'd it locally with what i believe is a reasonably up to date copy of the runtime (i don't think it is more than a week old)
Analysis
I'm aware the JIT has to throw for null in the first null case, but they show it has the ability to resolve it to a constant (it emits it as a constant load of 4
there, although right after throwing an NRE). It doesn't seem to succeed doing this with either a local (even when SkipLocalsInit
is enabled) or just with a pointer (where I would expect identical codegen to the null case, except comparing the pointer for null
rather than immediately NREing).
[module: SkipLocalsInit]
public struct Example
{
public byte Zero;
private byte _1, _2, _3;
public byte Four;
}
// good codegen :)! ... but instant null ref ex
public int OffsetAsNull()
{
Example* p = null;
return (int)(&p->Four - &p->Zero);
}
// bad codegen
public int OffsetAsNotNullWithLocal()
{
Example local;
Example* p = &local;
return (int)(&p->Four - &p->Zero);
}
// bad codegen
public int OffsetAsNotNullWithParam(Example* p)
{
return (int)(&p->Four - &p->Zero);
}
generates
C.OffsetAsNull()
L0000: xor eax, eax
L0002: cmp [eax], eax ; NRE
L0004: mov eax, 4 ; constant offset load
L0009: ret
C.OffsetAsNotNullWithLocal()
L0000: sub esp, 8
L0003: lea eax, [esp]
L0006: cmp [eax], eax
L0008: lea edx, [eax+4]
L000b: sub edx, eax
L000d: mov eax, edx
L000f: add esp, 8
L0012: ret
C.OffsetAsNotNullWithParam(Example*)
L0000: cmp [edx], edx
L0002: lea eax, [edx+4]
L0005: sub eax, edx ; it sets eax to edx + 4, then subs, but doesn't fold that to a constant?
L0007: ret
category:cq
theme:basic-cq
skill-level:intermediate
cost:medium
impact:small