JIT: fix interaction of OSR and shadowed parameters (#67884)
authorAndy Ayers <andya@microsoft.com>
Tue, 12 Apr 2022 15:59:36 +0000 (08:59 -0700)
committerGitHub <noreply@github.com>
Tue, 12 Apr 2022 15:59:36 +0000 (08:59 -0700)
If a Tier0 method has shadowed parameters, the patchpoint info it creates
must refer to the stack slots for the shadow copies. Otherwise any updates
made to the params by the Tier0 code will not be seen by the OSR method.

Fixes #67410.

src/coreclr/jit/compiler.cpp
src/tests/JIT/opt/OSR/shadowparam.cs [new file with mode: 0644]
src/tests/JIT/opt/OSR/shadowparam.csproj [new file with mode: 0644]

index c7d2158..ea036fc 100644 (file)
@@ -5276,7 +5276,23 @@ void Compiler::generatePatchpointInfo()
     // but would need to adjust all consumers, too.
     for (unsigned lclNum = 0; lclNum < info.compLocalsCount; lclNum++)
     {
-        LclVarDsc* const varDsc = lvaGetDesc(lclNum);
+        // If there are shadowed params, the patchpoint info should refer to the shadow copy.
+        //
+        unsigned varNum = lclNum;
+
+        if (gsShadowVarInfo != nullptr)
+        {
+            unsigned const shadowNum = gsShadowVarInfo[lclNum].shadowCopy;
+            if (shadowNum != BAD_VAR_NUM)
+            {
+                assert(shadowNum < lvaCount);
+                assert(shadowNum >= info.compLocalsCount);
+
+                varNum = shadowNum;
+            }
+        }
+
+        LclVarDsc* const varDsc = lvaGetDesc(varNum);
 
         // We expect all these to have stack homes, and be FP relative
         assert(varDsc->lvOnFrame);
@@ -5292,8 +5308,8 @@ void Compiler::generatePatchpointInfo()
             patchpointInfo->SetIsExposed(lclNum);
         }
 
-        JITDUMP("--OSR-- V%02u is at virtual offset %d%s\n", lclNum, patchpointInfo->Offset(lclNum),
-                patchpointInfo->IsExposed(lclNum) ? " (exposed)" : "");
+        JITDUMP("--OSR-- V%02u is at virtual offset %d%s%s\n", lclNum, patchpointInfo->Offset(lclNum),
+                patchpointInfo->IsExposed(lclNum) ? " (exposed)" : "", (varNum != lclNum) ? " (shadowed)" : "");
     }
 
     // Special offsets
diff --git a/src/tests/JIT/opt/OSR/shadowparam.cs b/src/tests/JIT/opt/OSR/shadowparam.cs
new file mode 100644 (file)
index 0000000..d43b2b8
--- /dev/null
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.CompilerServices;
+
+// F is an OSR method with parameter shadowing
+
+public unsafe struct ShadowParam
+{
+    public int a;
+    public fixed int data[2];
+    public int b;
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    public static int F(int x, string sa, ShadowParam u, string sb, int a, int b, int y)
+    {
+        for (int i = 0; i < a + b; i++)
+        {
+            x += u.data[0];
+        }
+
+        for (int i = 0; i < a + b; i++)
+        {
+            y += u.data[1];
+        }
+
+        return x + y + u.a + u.b + sb.Length - sa.Length;
+    }
+
+    public static int Main()
+    {
+        var u = new ShadowParam();
+        u.data[0] = 1;
+        u.data[1] = -1;
+        u.a = 3;
+        u.b = -3;
+
+        int r = F(0, "a", u, "b", 100_001, -1, 100);
+        Console.WriteLine($"Result is {r}");
+        return r;
+    }
+}
+
diff --git a/src/tests/JIT/opt/OSR/shadowparam.csproj b/src/tests/JIT/opt/OSR/shadowparam.csproj
new file mode 100644 (file)
index 0000000..2ab2ec6
--- /dev/null
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <DebugType />
+    <Optimize>True</Optimize>
+    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+</Project>