From b41e0e4210a8c02af76c9cb4660c9103f0218dfd Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Thu, 28 May 2026 06:30:01 -0700 Subject: [PATCH] JIT: Fix bug in GenTree::Equals (#128654) Make sure we properly distinguish virtual stub calls to avoid incorrect head/tail merges. Fixes #128631. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit dfd91b8a920820495f07b3529f350b46d9c2caef) --- src/coreclr/jit/gentree.cpp | 6 +++ .../JitBlue/Runtime_128631/Runtime_128631.cs | 43 +++++++++++++++++++ .../Runtime_128631/Runtime_128631.csproj | 9 ++++ 3 files changed, 58 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_128631/Runtime_128631.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_128631/Runtime_128631.csproj diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 2ae5c17f1132f7..7f6a1a3b9ce2d4 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -2485,6 +2485,12 @@ bool GenTreeCall::Equals(GenTreeCall* c1, GenTreeCall* c2) { return false; } + + // For virtual stub calls the stub addresses must agree. + if (c1->IsVirtualStub() && (c1->gtStubCallStubAddr != c2->gtStubCallStubAddr)) + { + return false; + } } else { diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_128631/Runtime_128631.cs b/src/tests/JIT/Regression/JitBlue/Runtime_128631/Runtime_128631.cs new file mode 100644 index 00000000000000..736bcb56988ea1 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_128631/Runtime_128631.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. + +// Two shared-generic interface call sites that canonicalize to __Canon must +// not be merged by head/tail merge: each call has a distinct virtual stub +// dispatch cell, so the calls are not interchangeable. + +namespace Runtime_128631; + +using System.Runtime.CompilerServices; +using Xunit; + +public interface IFoo { object Get(); } + +public class Impl : IFoo, IFoo +{ + [MethodImpl(MethodImplOptions.NoInlining)] object IFoo.Get() => "STRING_VALUE"; + [MethodImpl(MethodImplOptions.NoInlining)] object IFoo.Get() => new byte[] { 1, 2, 3 }; + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + public object Dispatch(string tag) + { + if (tag == "bytes") return ((IFoo)this).Get(); + if (tag == "string") return ((IFoo)this).Get(); + return null; + } +} + +public class Runtime_128631 +{ + [Fact] + public static int TestEntryPoint() + { + var d = new Impl(); + for (int i = 0; i < 200; i++) + { + d.Dispatch("bytes"); + d.Dispatch("string"); + } + object r = d.Dispatch("string"); + return r is string ? 100 : -1; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_128631/Runtime_128631.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_128631/Runtime_128631.csproj new file mode 100644 index 00000000000000..501217e4d86892 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_128631/Runtime_128631.csproj @@ -0,0 +1,9 @@ + + + None + True + + + + +