Repository: dotnet/runtime
Pull request #115844: JIT: also check gc-ness of layout for GT_BLK during escape analysis
Author: login: AndyAyersMS
Labels: name: area-CodeGen-coreclr
description: CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Created: 2025-05-21T16:08:33Z | Merged: 2025-05-22T14:45:29Z

Otherwise we may mistakenly build a connection to the unknown source and try retyping a non-gc struct.

Fixes #115831.

Linked issue #115831: JIT: Assertion failed 'newType == TYP_I_IMPL' during 'Allocate Objects'
```csharp
// Generated by Fuzzlyn v3.0 on 2025-05-20 21:40:51
// Run on X64 Windows
// Seed: 11262416476118799467-vectort,vector128,vector256,x86aes,x86avx,x86avx2,x86avx512bw,x86avx512bwvl,x86avx512cd,x86avx512cdvl,x86avx512dq,x86avx512dqvl,x86avx512f,x86avx512fvl,x86avx512fx64,x86bmi1,x86bmi1x64,x86bmi2,x86bmi2x64,x86fma,x86lzcnt,x86lzcntx64,x86pclmulqdq,x86popcnt,x86popcntx64,x86sse,x86ssex64,x86sse2,x86sse2x64,x86sse3,x86sse41,x86sse41x64,x86sse42,x86sse42x64,x86ssse3,x86x86base
// Reduced from 52.0 KiB to 0.5 KiB in 00:03:45
// Hits JIT assert in Release:
// Assertion failed 'newType == TYP_I_IMPL' in 'Program:Main(Fuzzlyn.ExecutionServer.IRuntime)' during 'Allocate Objects' (IL size 47; hash 0xade6b36b; FullOpts)
// 
//     File: D:\a\_work\1\s\src\coreclr\jit\objectalloc.cpp Line: 2427
// 
using System;
using System.Numerics;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;

public class C1
{
}

public struct S2
{
    public Vector<ushort> F0;
}

public struct S3
{
    public S2 F3;
    public C1 F5;
}

public class Program
{
    public static S3 s_1;
    public static void Main()
    {
        S3 vr0 = s_1;
        S2 vr1 = vr0.F3;
        vr0.F5 = new C1();
        System.Console.WriteLine(vr1.F0);
    }
}
```

cc @AndyAyersMS 
Linked issue comments: user: login: dotnet-policy-service[bot]
created_at: 2025-05-21T13:16:39Z
body: Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in [area-owners.md](https://github.com/dotnet/runtime/blob/main/docs/area-owners.md) if you want to be subscribed.
<!-- Policy app identification https://img.shields.io/static/v1?label=PullRequestIssueManagement. -->
author_association: CONTRIBUTOR

Diff:
diff --git a/src/coreclr/jit/objectalloc.cpp b/src/coreclr/jit/objectalloc.cpp
index 78ca1537d26a56..604049cb34a81d 100644
--- a/src/coreclr/jit/objectalloc.cpp
+++ b/src/coreclr/jit/objectalloc.cpp
@@ -1906,6 +1906,19 @@ void ObjectAllocator::AnalyzeParentStack(ArrayStack<GenTree*>* parentStack, unsi
                     break;
                 }
 
+                // For structs we need to check the layout as well
+                //
+                if (parent->OperIs(GT_BLK))
+                {
+                    ClassLayout* const layout = parent->AsBlk()->GetLayout();
+
+                    if (!layout->HasGCPtr())
+                    {
+                        canLclVarEscapeViaParentStack = false;
+                        break;
+                    }
+                }
+
                 GenTree* const addr = parent->AsIndir()->Addr();
 
                 // For loads from local structs we may be tracking the underlying fields.
diff --git a/src/tests/JIT/opt/ObjectStackAllocation/Runtime_115831.cs b/src/tests/JIT/opt/ObjectStackAllocation/Runtime_115831.cs
new file mode 100644
index 00000000000000..cf1d758f1e4201
--- /dev/null
+++ b/src/tests/JIT/opt/ObjectStackAllocation/Runtime_115831.cs
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// Generated by Fuzzlyn v3.0 on 2025-05-20 21:40:51
+// Run on X64 Windows
+// Seed: 11262416476118799467-vectort,vector128,vector256,x86aes,x86avx,x86avx2,x86avx512bw,x86avx512bwvl,x86avx512cd,x86avx512cdvl,x86avx512dq,x86avx512dqvl,x86avx512f,x86avx512fvl,x86avx512fx64,x86bmi1,x86bmi1x64,x86bmi2,x86bmi2x64,x86fma,x86lzcnt,x86lzcntx64,x86pclmulqdq,x86popcnt,x86popcntx64,x86sse,x86ssex64,x86sse2,x86sse2x64,x86sse3,x86sse41,x86sse41x64,x86sse42,x86sse42x64,x86ssse3,x86x86base
+// Reduced from 52.0 KiB to 0.5 KiB in 00:03:45
+// Hits JIT assert in Release:
+// Assertion failed 'newType == TYP_I_IMPL' in 'Program:Main(Fuzzlyn.ExecutionServer.IRuntime)' during 'Allocate Objects' (IL size 47; hash 0xade6b36b; FullOpts)
+// 
+//     File: D:\a\_work\1\s\src\coreclr\jit\objectalloc.cpp Line: 2427
+// 
+using System;
+using System.Numerics;
+using Xunit;
+
+public class C1
+{
+}
+
+public struct S2
+{
+    public Vector<ushort> F0;
+}
+
+public struct S3
+{
+    public S2 F3;
+    public C1 F5;
+}
+
+public class Runtime_115831
+{
+    public static S3 s_1;
+    [Fact]
+    public static void Problem()
+    {
+        S3 vr0 = s_1;
+        S2 vr1 = vr0.F3;
+        vr0.F5 = new C1();
+        System.Console.WriteLine(vr1.F0);
+    }
+}
\ No newline at end of file
diff --git a/src/tests/JIT/opt/ObjectStackAllocation/Runtime_115831.csproj b/src/tests/JIT/opt/ObjectStackAllocation/Runtime_115831.csproj
new file mode 100644
index 00000000000000..501217e4d86892
--- /dev/null
+++ b/src/tests/JIT/opt/ObjectStackAllocation/Runtime_115831.csproj
@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <DebugType>None</DebugType>
+    <Optimize>True</Optimize>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+</Project>


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR fixes an escape analysis issue in the JIT by checking the GC‐ness of a struct's layout for GT_BLK nodes, preventing misclassification of non-GC structs.  
- Introduces additional logic in objectalloc.cpp to inspect a block's layout for GC pointers.  
- Adds a new test case to validate the new behavior and updates the test project configuration.

### Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

| File | Description |
| ---- | ----------- |
| src/tests/JIT/opt/ObjectStackAllocation/Runtime_115831.csproj | Adds project configuration for the test |
| src/tests/JIT/opt/ObjectStackAllocation/Runtime_115831.cs | New test validating escape analysis behavior |
| src/coreclr/jit/objectalloc.cpp | Updates the escape analysis logic to check GC layout for GT_BLK |




state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T16:09:00Z
user: login: AndyAyersMS
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-21T16:15:52Z
user: login: jakobbotsch
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-22T08:21:26Z

Review comments:
diff_hunk: @@ -1906,6 +1906,19 @@ void ObjectAllocator::AnalyzeParentStack(ArrayStack<GenTree*>* parentStack, unsi
                     break;
                 }
 
+                // For structs we need to check the layout as well
+                //
+                if (parent->OperIs(GT_BLK))
+                {
+                    ClassLayout* const layout = parent->AsBlk()->GetLayout();
+
+                    if (!layout->HasGCPtr())
path: src/coreclr/jit/objectalloc.cpp
user: login: Copilot
body: Consider adding an assert or a null-check for 'layout' before calling 'HasGCPtr()', unless its non-null invariant is guaranteed elsewhere in the code.
```suggestion
                    if (layout == nullptr || !layout->HasGCPtr())
```
created_at: 2025-05-21T16:09:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1906,6 +1906,19 @@ void ObjectAllocator::AnalyzeParentStack(ArrayStack<GenTree*>* parentStack, unsi
                     break;
                 }
 
+                // For structs we need to check the layout as well
+                //
+                if (parent->OperIs(GT_BLK))
+                {
+                    ClassLayout* const layout = parent->AsBlk()->GetLayout();
+
+                    if (!layout->HasGCPtr())
path: src/coreclr/jit/objectalloc.cpp
user: login: AndyAyersMS
body: Layouts for GT_BLK are not nullptr; this is asserted in `GetLayout`.
created_at: 2025-05-21T16:15:52Z
author_association: MEMBER

PR comments:
user: login: dotnet-policy-service[bot]
created_at: 2025-05-21T16:09:21Z
body: Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in [area-owners.md](https://github.com/dotnet/runtime/blob/main/docs/area-owners.md) if you want to be subscribed.
<!-- Policy app identification https://img.shields.io/static/v1?label=PullRequestIssueManagement. -->
author_association: CONTRIBUTOR
user: login: AndyAyersMS
created_at: 2025-05-21T16:10:21Z
body: @dotnet/jit-contrib PTAL

Recent "regression" from #115689.

No [diffs](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1047702&view=ms.vss-build-web.run-extensions-tab) but a lot of missed contexts.
author_association: MEMBER
user: login: AndyAyersMS
created_at: 2025-05-22T00:09:09Z
body: @dotnet/jit-contrib ping
author_association: MEMBER