diff options
3 files changed, 115 insertions, 2 deletions
diff --git a/src/linker/Linker.Steps/RemoveUnreachableBlocksStep.cs b/src/linker/Linker.Steps/RemoveUnreachableBlocksStep.cs index 7aaa19a18..188389fee 100644 --- a/src/linker/Linker.Steps/RemoveUnreachableBlocksStep.cs +++ b/src/linker/Linker.Steps/RemoveUnreachableBlocksStep.cs @@ -339,6 +339,9 @@ namespace Mono.Linker.Steps continue; if (left is int lint && right is int rint) { + if (IsJumpTargetRange (i - 1, i)) + continue; + RewriteToNop (i - 2); RewriteToNop (i - 1); @@ -358,6 +361,9 @@ namespace Mono.Linker.Steps if (opcode.StackBehaviourPop == StackBehaviour.Popi) { if (i > 0 && GetConstantValue (FoldedInstructions [i - 1], out var operand)) { if (operand is int opint) { + if (IsJumpTargetRange (i, i)) + continue; + RewriteToNop (i - 1); if (IsConstantBranch (opcode, opint)) { @@ -371,6 +377,9 @@ namespace Mono.Linker.Steps } if (operand is null && (opcode.Code == Code.Brfalse || opcode.Code == Code.Brfalse_S)) { + if (IsJumpTargetRange (i, i)) + continue; + RewriteToNop (i - 1); Rewrite (i, Instruction.Create (OpCodes.Br, (Instruction)instr.Operand)); changed = true; @@ -380,6 +389,9 @@ namespace Mono.Linker.Steps // Common pattern generated by C# compiler in debug mode if (i > 3 && GetConstantValue (FoldedInstructions [i - 3], out operand) && operand is int opint2 && IsPairedStlocLdloc (FoldedInstructions [i - 2], FoldedInstructions [i - 1])) { + if (IsJumpTargetRange (i - 2, i)) + continue; + RewriteToNop (i - 3); RewriteToNop (i - 2); RewriteToNop (i - 1); @@ -409,6 +421,9 @@ namespace Mono.Linker.Steps continue; if (left is int lint && right is int rint) { + if (IsJumpTargetRange (i - 1, i)) + continue; + RewriteToNop (i - 2); RewriteToNop (i - 1); @@ -427,6 +442,9 @@ namespace Mono.Linker.Steps if (!GetOperandsConstantValues (i, out left, out right)) continue; + if (IsJumpTargetRange (i - 1, i)) + continue; + if (left == null && right == null) { Rewrite (i, Instruction.Create (OpCodes.Ldc_I4_0)); } @@ -689,6 +707,31 @@ namespace Mono.Linker.Steps throw new NotImplementedException (opCode.ToString ()); } + + bool IsJumpTargetRange (int firstInstr, int lastInstr) + { + foreach (var instr in FoldedInstructions) { + switch (instr.OpCode.FlowControl) { + case FlowControl.Branch: + case FlowControl.Cond_Branch: + if (instr.Operand is Instruction target) { + var index = GetInstructionIndex (target); + if (index >= firstInstr && index <= lastInstr) + return true; + } else { + foreach (var rtarget in (Instruction [])instr.Operand) { + var index = GetInstructionIndex (rtarget); + if (index >= firstInstr && index <= lastInstr) + return true; + } + } + + break; + } + } + + return false; + } } struct BodySweeper diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditions.cs b/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditions.cs index 9a92ab742..2660b240d 100644 --- a/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditions.cs +++ b/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditions.cs @@ -1,18 +1,46 @@ using System; using System.Reflection.Emit; using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; namespace Mono.Linker.Tests.Cases.UnreachableBlock { + [SetupCompileArgument ("/optimize-")] // Relying on debug csc behaviour public class ComplexConditions { - public static void Main() + public static void Main () { Test_1 (null); + Test_2 (9); } [Kept] +#if !NETCOREAPP [ExpectBodyModified] +#else + [ExpectedInstructionSequence (new [] { + "nop", + "ldarg.0", + "isinst", + "brtrue.s", + "call", + "pop", + "ldarg.0", + "isinst", + "ldnull", + "cgt.un", + "br.s", + "nop", + "br.s", + "ldc.i4.1", + "stloc.0", + "ldloc.0", + "brfalse.s", + "call", + "nop", + "ret" + })] +#endif static void Test_1 (object type) { if (type is Type || (IsDynamicCodeSupported && type is TypeBuilder)) @@ -20,6 +48,47 @@ namespace Mono.Linker.Tests.Cases.UnreachableBlock } [Kept] +#if !NETCOREAPP + [ExpectBodyModified] +#else + [ExpectedInstructionSequence (new [] { + "nop", + "call", + "stloc.1", + "ldloc.1", + "pop", + "ldc.i4.0", + "stloc.0", + "ldarg.0", + "ldc.i4.2", + "beq.s", + "ldarg.0", + "ldc.i4.3", + "ceq", + "br.s", + "ldc.i4.1", + "stloc.2", + "ldloc.2", + "brfalse.s", + "newobj", + "throw", + "newobj", + "throw" + })] +#endif + static void Test_2 (int a) + { + int zero; + if (IsDynamicCodeSupported) + zero = 0; + + if (a == 2 || a == 3) + throw new ArgumentException (); + + throw new ApplicationException (); + } + + [Kept] static bool IsDynamicCodeSupported { [Kept] get { @@ -29,7 +98,7 @@ namespace Mono.Linker.Tests.Cases.UnreachableBlock [Kept] static void Reached_1 () - { + { } } }
\ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBlock/SimpleConditionalProperty.cs b/test/Mono.Linker.Tests.Cases/UnreachableBlock/SimpleConditionalProperty.cs index f95a67a14..1b0eaad0d 100644 --- a/test/Mono.Linker.Tests.Cases/UnreachableBlock/SimpleConditionalProperty.cs +++ b/test/Mono.Linker.Tests.Cases/UnreachableBlock/SimpleConditionalProperty.cs @@ -5,6 +5,7 @@ using Mono.Linker.Tests.Cases.Expectations.Metadata; namespace Mono.Linker.Tests.Cases.UnreachableBlock { // [SetupCSharpCompilerToUse ("csc")] + [SetupCompileArgument ("/optimize+")] public class SimpleConditionalProperty { public static void Main() |