diff options
4 files changed, 180 insertions, 27 deletions
diff --git a/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs b/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs index 91f4b61bb..b1adf6de6 100644 --- a/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs +++ b/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -202,7 +202,7 @@ namespace Mono.Linker.Steps return null; case MethodAction.ConvertToStub: Instruction? constant = CodeRewriterStep.CreateConstantResultInstruction (_context, method); - return constant == null ? null : new MethodResult (constant, true); + return constant == null ? null : new MethodResult (constant, !HasSideEffects (method)); } if (method.IsIntrinsic () || method.NoInlining) @@ -212,13 +212,16 @@ namespace Mono.Linker.Steps return null; var analyzer = new ConstantExpressionMethodAnalyzer (this); - if (analyzer.Analyze (callee, callStack)) { + if (analyzer.Analyze (callee, callStack)) return new MethodResult (analyzer.Result, analyzer.SideEffectFreeResult); - } return null; } + static bool HasSideEffects (MethodDefinition method) + { + return !method.DeclaringType.IsBeforeFieldInit; + } // // Return expression with a value when method implementation can be @@ -457,15 +460,8 @@ namespace Mono.Linker.Steps if (call_result is not MethodResult result) break; - if (!result.IsSideEffectFree) - break; - - TypeDefinition methodType = md.DeclaringType; - if (methodType != body.Method.DeclaringType && !methodType.IsBeforeFieldInit) { - // - // Figuring out at this point if the explicit static ctor will be used is hard - // - optimizer._context.LogMessage ($"Cannot inline result of '{md.GetDisplayName ()}' call due to presence of static constructor"); + if (!result.IsSideEffectFree) { + optimizer._context.LogMessage ($"Cannot inline constant result of '{md.GetDisplayName ()}' call due to presence of side effects"); break; } @@ -1401,6 +1397,8 @@ namespace Mono.Linker.Steps Instruction? linstr; object? left, right, operand; + SideEffectFreeResult = !HasSideEffects (method); + // // We could implement a full-blown interpreter here but for now, it handles // cases used in runtime libraries diff --git a/test/Mono.Linker.Tests.Cases/FeatureSettings/FeatureSubstitutionsNested.cs b/test/Mono.Linker.Tests.Cases/FeatureSettings/FeatureSubstitutionsNested.cs index b9a4f1c13..204f48df8 100644 --- a/test/Mono.Linker.Tests.Cases/FeatureSettings/FeatureSubstitutionsNested.cs +++ b/test/Mono.Linker.Tests.Cases/FeatureSettings/FeatureSubstitutionsNested.cs @@ -15,24 +15,11 @@ namespace Mono.Linker.Tests.Cases.FeatureSettings [SetupLinkerArgument ("--feature", "MethodCondition", "false")] [SetupLinkerArgument ("--feature", "FieldCondition", "true")] [SetupLinkerArgument ("--feature", "ResourceCondition", "true")] + [SetupLinkerArgument ("--enable-opt", "ipconstprop")] [RemovedResourceInAssembly ("test.exe", "ResourceFileRemoveWhenTrue.txt")] [KeptResource ("ResourceFileRemoveWhenFalse.txt")] public class FeatureSubstitutionsNested { - [ExpectedInstructionSequence (new[] { - "nop", - "ldc.i4.1", - "pop", - "ldc.i4.0", - "pop", - "ldc.i4.1", - "pop", - "ldc.i4.0", - "pop", - "ldsfld System.Boolean Mono.Linker.Tests.Cases.FeatureSettings.FeatureSubstitutionsNested::FieldConditionField", - "pop", - "ret", - })] public static void Main () { GlobalConditionMethod (); @@ -42,21 +29,41 @@ namespace Mono.Linker.Tests.Cases.FeatureSettings _ = FieldConditionField; } + [Kept] + [ExpectedInstructionSequence (new[] { + "ldc.i4.1", + "ret", + })] static bool GlobalConditionMethod () { throw new NotImplementedException (); } + [Kept] + [ExpectedInstructionSequence (new[] { + "ldc.i4.0", + "ret", + })] static bool AssemblyConditionMethod () { throw new NotImplementedException (); } + [Kept] + [ExpectedInstructionSequence (new[] { + "ldc.i4.1", + "ret", + })] static bool TypeConditionMethod () { throw new NotImplementedException (); } + [Kept] + [ExpectedInstructionSequence (new[] { + "ldc.i4.0", + "ret", + })] static bool MethodConditionMethod () { throw new NotImplementedException (); diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/StubBodyWithStaticCtor.cs b/test/Mono.Linker.Tests.Cases/Substitutions/StubBodyWithStaticCtor.cs new file mode 100644 index 000000000..8cb9b3621 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Substitutions/StubBodyWithStaticCtor.cs @@ -0,0 +1,136 @@ +using System; +using System.Runtime.CompilerServices; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.Substitutions +{ + [SetupLinkerSubstitutionFile ("StubBodyWithStaticCtor.xml")] + [SetupCompileArgument ("/optimize+")] + [SetupLinkerArgument ("--enable-opt", "ipconstprop")] + public class StubBodyWithStaticCtor + { + public static void Main () + { + TestMethod_1 (); + TestMethod_2 (); + TestMethod_3 (); + } + + [Kept] + [ExpectedInstructionSequence (new[] { + "call System.Int32 Mono.Linker.Tests.Cases.Substitutions.StubBodyWithStaticCtorImpl::TestMethod()", + "ldc.i4.2", + "beq.s il_8", + "ldc.i4.3", + "ret", + })] + static int TestMethod_1 () + { + if (StubBodyWithStaticCtorImpl.TestMethod () != 2) { + Console.WriteLine (); + return 1; + } + + return 3; + } + + [Kept] + [ExpectedInstructionSequence (new[] { + "call System.Int32 Mono.Linker.Tests.Cases.Substitutions.IntermediateClass::GetValue()", + "ldc.i4.2", + "beq.s il_8", + "ldc.i4.3", + "ret", + })] + static int TestMethod_2 () + { + if (IntermediateClass.GetValue () != 2) { + Console.WriteLine (); + return 1; + } + + return 3; + } + + [Kept] + [ExpectedInstructionSequence (new[] { + "call System.Boolean Mono.Linker.Tests.Cases.Substitutions.WrappingClass::GetValue()", + "brfalse.s il_7", + "ldc.i4.3", + "ret", + })] + static int TestMethod_3 () + { + if (WrappingClass.GetValue ()) { + Console.WriteLine (); + return 1; + } + + return 3; + } + } + + [Kept] + class WrappingClass + { + [Kept] + public static bool GetValue () + { + return Settings.TestValue (); + } + + static class Settings + { + [Kept] + static Settings () + { + Console.WriteLine (); + } + + [Kept] + [ExpectedInstructionSequence (new[] { + "ldc.i4.0", + "ret", + })] + public static bool TestValue () + { + throw new NotImplementedException (); + } + } + } + + [Kept] + class StubBodyWithStaticCtorImpl + { + [Kept] + public static int count; + + [Kept] + static StubBodyWithStaticCtorImpl () + { + count = 100; + } + + [Kept] + [ExpectedInstructionSequence (new[] { + "ldc.i4 0x2", + "ret", + })] + public static int TestMethod () + { + ++count; + return Environment.ExitCode; + } + } + + [Kept] + class IntermediateClass + { + [Kept] + public static int GetValue () + { + return StubBodyWithStaticCtorImpl.TestMethod (); + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/StubBodyWithStaticCtor.xml b/test/Mono.Linker.Tests.Cases/Substitutions/StubBodyWithStaticCtor.xml new file mode 100644 index 000000000..5fb03c8c4 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Substitutions/StubBodyWithStaticCtor.xml @@ -0,0 +1,12 @@ +<linker> + <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> + <type fullname="Mono.Linker.Tests.Cases.Substitutions.StubBodyWithStaticCtorImpl"> + <method signature="System.Int32 TestMethod()" body="stub" value="2"> + </method> + </type> + <type fullname="Mono.Linker.Tests.Cases.Substitutions.WrappingClass/Settings"> + <method signature="System.Boolean TestValue()" body="stub" value="false"> + </method> + </type> + </assembly> +</linker> |