diff --git a/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs b/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs index 28eb66f1513b..2d9097f975df 100644 --- a/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs +++ b/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs @@ -617,7 +617,7 @@ void RewriteCondition (int index, Instruction instr, int operand) case Code.Switch: var targets = (Instruction[]) instr.Operand; - if (operand <= targets.Length) { + if (operand < targets.Length) { // It does not need to be conditional but existing logic in BodySweeper would // need to be updated to deal with 1->2 instruction replacement RewriteConditionTo (index, Instruction.Create (operand == 0 ? OpCodes.Brfalse : OpCodes.Brtrue, targets[operand])); diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditionsOptimized.cs b/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditionsOptimized.cs index 1161e757644b..951243ab458d 100644 --- a/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditionsOptimized.cs +++ b/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditionsOptimized.cs @@ -1,5 +1,6 @@ using System; using System.Reflection.Emit; +using System.Runtime.InteropServices; using System.Runtime.Serialization; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; @@ -17,6 +18,7 @@ public static void Main () TestSwitch.TestOffset (); TestSwitch2.TestFallThrough (); TestSwitchZero.Test (); + TestSwitch3.TestFallThrough (true); } [Kept] @@ -125,6 +127,54 @@ public static void TestFallThrough () static void Unreached () { } } + [Kept] + class TestSwitch3 + { + [Kept] + [ExpectedInstructionSequence (new[] { + "ldc.i4.4", + "stloc.0", + "ldloc.0", + "pop", + "br.s il_6", + "newobj System.Void System.NotSupportedException::.ctor()", + "throw", + })] + public static object TestFallThrough (bool createReader) + { + object instance; + + switch (ProcessArchitecture, createReader) { + case (Architecture.X86, true): + Unreached (); + break; + case (Architecture.X86, false): + Unreached (); + break; + case (Architecture.X64, true): + Unreached (); + break; + case (Architecture.X64, false): + Unreached (); + break; + case (Architecture.Arm64, true): + Unreached (); + break; + case (Architecture.Arm64, false): + Unreached (); + break; + default: + throw new NotSupportedException (); + } + + return null; + } + + static Architecture ProcessArchitecture => Architecture.Wasm; + + static void Unreached () { } + } + [Kept] class TestSwitchZero {