From: Andy Ayers Date: Mon, 10 Apr 2017 19:05:49 +0000 (-0700) Subject: Jit: fix issue with single-def type propagation X-Git-Tag: submit/tizen/20210909.063632~11030^2~7307^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2efa50a403e13a4cea4c38b6c8d6463f2cb06f87;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Jit: fix issue with single-def type propagation To avoid overly aggressive type propagation when there are multiple reaching definitions, only propagate types to single-IL-def locals when the definiting value comes from the same basic block as the store. We check this conservatively by insisting that the block's entry stack be empty. Added a test case where the jit will improperly devirtualize without such a check. Closes dotnet/coreclr#10858. Commit migrated from https://github.com/dotnet/coreclr/commit/a9044a132b4807695d386181cf55bb952826e350 --- diff --git a/src/coreclr/src/jit/importer.cpp b/src/coreclr/src/jit/importer.cpp index 64c6f45..d47e3df 100644 --- a/src/coreclr/src/jit/importer.cpp +++ b/src/coreclr/src/jit/importer.cpp @@ -10094,7 +10094,11 @@ void Compiler::impImportBlockCode(BasicBlock* block) const bool isSingleILStoreLocal = !lvaTable[lclNum].lvHasMultipleILStoreOp && !lvaTable[lclNum].lvHasLdAddrOp; - if (isSingleILStoreLocal) + // Conservative check that there is just one + // definition that reaches this store. + const bool hasSingleReachingDef = (block->bbStackDepthOnEntry() == 0); + + if (isSingleILStoreLocal && hasSingleReachingDef) { lvaUpdateClass(lclNum, op1, clsHnd); } diff --git a/src/coreclr/tests/src/JIT/opt/Devirtualization/GitHub_10858.cs b/src/coreclr/tests/src/JIT/opt/Devirtualization/GitHub_10858.cs new file mode 100644 index 0000000..a02d025 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/Devirtualization/GitHub_10858.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +class B +{ + public virtual string F() { return "B"; } +} + +sealed class D : B +{ + public override string F() { return "D"; } +} + +sealed class E : B +{ + public override string F() { return "E"; } +} + +class X +{ + public static int Main(string[] args) + { + // When optimizing IL, CSC will leave the newobj's on the stack + // across the branches to the common def point. + B b1 = (args.Length > 0) ? (B)new E() : (B)new D(); + B b2 = null; + + // Conditional flow here to forces b1 to a local instead of + // remaining on the stack. So we have a single def point with + // two reaching values. + if (args.Length > 0) + { + b2 = new D(); + } + else + { + b2 = new E(); + } + + // We should not be able to devirtualize either call. + return b2.F()[0] + b1.F()[0] - 37; + } +} diff --git a/src/coreclr/tests/src/JIT/opt/Devirtualization/GitHub_10858.csproj b/src/coreclr/tests/src/JIT/opt/Devirtualization/GitHub_10858.csproj new file mode 100644 index 0000000..fdf04a2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/Devirtualization/GitHub_10858.csproj @@ -0,0 +1,37 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + + + False + + + + None + True + + + + + + + + + + +