Skip to content

Resolve field offsets through byref bases in ResolveFieldOffsets - #613

Open
shadesbelow wants to merge 1 commit into
SamboyCoding:developmentfrom
shadesbelow:byref-field-offset-resolution
Open

Resolve field offsets through byref bases in ResolveFieldOffsets#613
shadesbelow wants to merge 1 commit into
SamboyCoding:developmentfrom
shadesbelow:byref-field-offset-resolution

Conversation

@shadesbelow

Copy link
Copy Markdown

ResolveFieldOffsets only succeeds when the memory operand's base local has a normal instance type with a populated .Fields list. When the base is a ByRefTypeAnalysisContext (a T& local — e.g. a ref MyStruct data parameter), .Fields is always empty, because the byref wrapper is a ReferencedTypeAnalysisContext with no Definition.

The offset therefore never resolves, and every field read through that ref parameter falls through to the Unmanaged memory load diagnostic — even though Ldfld accepts a managed pointer operand directly, which is the same precedent IlGenerator's addend == 0 byref dereference case already relies on.

This resolves field offsets against the referent (.ElementType) when the base is a byref, rather than against the byref wrapper itself.

Measured

On a shipped Unity 6 IL2CPP title (x86-64, metadata v31), with only this diff toggled:

sites
Unmanaged memory load before 20,807
after 20,336
eliminated 471

Verified rather than just gate-passed: one newly-resolved site (a byref base + 0x1C) was checked against Il2CppInspector's dumped field layout for the same struct, which lists a field at 0x1C. Exact match. A single heavy ref consumer in that title drops from 394 to 200 diagnostic sites.

The remainder of the 20,336 is a different problem (generic value-type layout and Il2CppClass runtime-metadata reads) and is deliberately left as diagnostics rather than guessed.

ResolveFieldOffsets only succeeds when the memory operand's base local has a
normal instance type with a populated .Fields list. When the base is a
ByRefTypeAnalysisContext (a T& local - e.g. a `ref MyStruct data` parameter),
.Fields is always empty, because the byref wrapper is a
ReferencedTypeAnalysisContext with no Definition. The offset therefore never
resolves, and every field read through that ref parameter falls through to the
"Unmanaged memory load" diagnostic - even though Ldfld accepts a managed
pointer operand directly, which is the same precedent IlGenerator's addend==0
byref dereference case already relies on.

Resolve field offsets against the referent (.ElementType) when the base is a
byref, rather than against the byref wrapper itself.

Measured on a shipped Unity 6 IL2CPP title (x86-64, metadata v31): 20,807 ->
20,336 "Unmanaged memory load" sites, i.e. 471 eliminated. Spot-checked one
newly-resolved site against Il2CppInspector's dumped field layout for the same
struct: byref base + 0x1C resolved to the field the dump lists at 0x1C.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant