diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 7b849454fc00ff..b35d009f20ef58 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -9224,7 +9224,14 @@ void Compiler::impMarkInlineCandidate(GenTree* callNode, for (uint8_t candidateId = 0; candidateId < call->GetInlineCandidatesCount(); candidateId++) { - InlineResult inlineResult(this, call, nullptr, "impMarkInlineCandidate for GDV"); + InlineCandidateInfo* gdvCandidate = call->GetGDVCandidateInfo(candidateId); + CORINFO_METHOD_HANDLE callee = gdvCandidate->guardedMethodUnboxedResolvedToken.hMethod; + if (callee == nullptr) + { + callee = gdvCandidate->guardedMethodHandle; + } + + InlineResult inlineResult(this, call, nullptr, "impMarkInlineCandidate for GDV", false, callee); // Do the actual evaluation impMarkInlineCandidateHelper(call, candidateId, exactContextHnd, callInfo, inlinersContext, &inlineResult); diff --git a/src/coreclr/jit/inline.cpp b/src/coreclr/jit/inline.cpp index 91535236bc27f5..150fa17a8740da 100644 --- a/src/coreclr/jit/inline.cpp +++ b/src/coreclr/jit/inline.cpp @@ -640,15 +640,20 @@ void InlineContext::DumpXml(FILE* file, unsigned indent) // call - the call in question // stmt - statement containing the call (if known) // description - string describing the context of the decision - -InlineResult::InlineResult( - Compiler* compiler, GenTreeCall* call, Statement* stmt, const char* description, bool doNotReport) +// callee - the actual inline candidate, if different from the call target + +InlineResult::InlineResult(Compiler* compiler, + GenTreeCall* call, + Statement* stmt, + const char* description, + bool doNotReport, + CORINFO_METHOD_HANDLE callee) : m_RootCompiler(nullptr) , m_Policy(nullptr) , m_Call(call) , m_InlineContext(nullptr) , m_Caller(nullptr) - , m_Callee(nullptr) + , m_Callee(callee) , m_ImportedILSize(0) , m_Description(description) , m_successResult(INLINE_PASS) @@ -689,7 +694,7 @@ InlineResult::InlineResult( m_Caller = compiler->info.compMethodHnd; // Get method handle for callee, if known - if (m_Call->AsCall()->gtCallType == CT_USER_FUNC) + if ((m_Callee == nullptr) && (m_Call->AsCall()->gtCallType == CT_USER_FUNC)) { m_Callee = m_Call->AsCall()->gtCallMethHnd; } diff --git a/src/coreclr/jit/inline.h b/src/coreclr/jit/inline.h index 28452a567fb1de..ef1f93c45235c7 100644 --- a/src/coreclr/jit/inline.h +++ b/src/coreclr/jit/inline.h @@ -344,8 +344,12 @@ class InlineResult public: // Construct a new InlineResult to help evaluate a // particular call for inlining. - InlineResult( - Compiler* compiler, GenTreeCall* call, Statement* stmt, const char* description, bool doNotReport = false); + InlineResult(Compiler* compiler, + GenTreeCall* call, + Statement* stmt, + const char* description, + bool doNotReport = false, + CORINFO_METHOD_HANDLE callee = nullptr); // Construct a new InlineResult to evaluate a particular // method to see if it is inlineable. diff --git a/src/tests/JIT/opt/GuardedDevirtualization/badinlinee.cs b/src/tests/JIT/opt/GuardedDevirtualization/badinlinee.cs new file mode 100644 index 00000000000000..8dbdc9195bcc71 --- /dev/null +++ b/src/tests/JIT/opt/GuardedDevirtualization/badinlinee.cs @@ -0,0 +1,75 @@ +// 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; +using System.Threading; +using Xunit; + +public class BadInlinee +{ + private class Base + { + public virtual int M() => 42; + } + + private sealed class Derived : Base + { + [MethodImpl(MethodImplOptions.Synchronized)] + public override int M() => 43; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static int Poison(Base value) => value.M(); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static int Test() + { + Base value = new Base(); + return value.M(); + } + + [Fact] + public static int TestEntryPoint() + { + Base value = new Derived(); + int result = 0; + + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 100; j++) + { + result += Poison(value); + } + + Thread.Sleep(15); + } + + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 100; j++) + { + result += Test(); + } + + Thread.Sleep(15); + } + + long allocatedBytesBefore = GC.GetAllocatedBytesForCurrentThread(); + + for (int i = 0; i < 1_000; i++) + { + result += Test(); + } + + long allocatedBytes = GC.GetAllocatedBytesForCurrentThread() - allocatedBytesBefore; + + if (allocatedBytes != 0) + { + Console.WriteLine($"Test allocated {allocatedBytes} bytes"); + return -1; + } + + return result == 892_000 ? 100 : -1; + } +} diff --git a/src/tests/JIT/opt/GuardedDevirtualization/badinlinee.csproj b/src/tests/JIT/opt/GuardedDevirtualization/badinlinee.csproj new file mode 100644 index 00000000000000..5d2eec4b7dbfae --- /dev/null +++ b/src/tests/JIT/opt/GuardedDevirtualization/badinlinee.csproj @@ -0,0 +1,15 @@ + + + 1 + True + true + + + + + + + + + +