dotnet / dotnet/runtime

JIT Escape Analysis: cyclic reference assignments force heap allocation; cannot eliminate escapes in simple mutual-linking case

Open
#123,132 2 comments 0 reactions 0 assignees View on GitHub
area-CodeGen-coreclr
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Description

JIT Escape Analysis: cyclic reference assignments force heap allocation; cannot eliminate escapes in simple mutual-linking case

### Reproduction Steps

```
TestEscapeLogic.TestEscape2();

public class A { public int Field1; public object Data; }

public class B { public int Field2; public object Data; }

public static class TestEscapeLogic
{
[MethodImpl(MethodImplOptions.NoInlining)]
public static int TestEscape2()
{
var a = new A();
var b = new B();
a.Data = b;
b.Data = a;
return a.Field1 + b.Field2;
}
}
```
Build

```
"DOTNET_JitDisasm": "*TestEscape*",
"DOTNET_TieredCompilation": "0",
"DOTNET_ReadyToRun": "0"

dotnet run -c Release --launch-profile JitDisasm --framework net10.0
; Assembly listing for method TestEscapeLogic:TestEscape3():int (FullOpts)
; Emitting BLENDED_CODE for generic ARM64 on Apple
; FullOpts code
; optimized code
; fp based frame
; partially interruptible
; No PGO data
; 0 inlinees with PGO data; 6 single block inlinees; 0 inlinees without PGO data

G_M000_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x20]!
stp x19, x20, [sp, #0x10]
mov fp, sp

G_M000_IG02: ;; offset=0x000C
movz x19, #0x4CC8
movk x19, #0x744 LSL #16
movk x19, #1 LSL #32
mov x0, x19
bl CORINFO_HELP_NEWSFAST
mov x20, x0
sub x0, x19, #208
bl CORINFO_HELP_NEWSFAST
add x14, x20, #8
mov x15, x0
bl CORINFO_HELP_ASSIGN_REF
add x14, x0, #8
mov x15, x20
bl CORINFO_HELP_ASSIGN_REF
ldr w1, [x20, #0x10]
ldr w0, [x0, #0x10]
add w0, w1, w0

G_M000_IG03: ;; offset=0x0050
ldp x19, x20, [sp, #0x10]
ldp fp, lr, [sp], #0x20
ret lr

; Total bytes of code 92
```

### Expected behavior

JIT should prove that a and b do not escape the method and:

either eliminate both allocations entirely (scalar replacement), or

stack allocate them (object stack allocation), since the cycle is local and unobservable.

```
G_M000_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x10]!
mov fp, sp

G_M000_IG02: ;; offset=0x0008
mov w0, wzr

G_M000_IG03: ;; offset=0x000C
ldp fp, lr, [sp], #0x10
ret lr

; Total bytes of code 20
```

### Actual behavior

Both objects are treated as escaping / remain heap allocated (allocations are not removed)

### Regression?

_No response_

### Known Workarounds

_No response_

### Configuration

_No response_

### Other information

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.