From c84605a610b9d2f361f09cae43bd23073e235e84 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 23 Aug 2025 18:25:27 +0200 Subject: [PATCH] Fix #3468: Try harder to avoid ref locals if `UseRefLocalsForAccurateOrderOfEvaluation` is not enabled. CopyPropagation will replace `ref StructWithStringField reference = ref array[0];` with: ``` var x = array; var y = 0; ``` and then every use of `reference` is replaced with `x[y]`. This lets us avoid rough locals while preserving the semantics in every case except that we re-order when a NullReferenceException/IndexOutOfRangeException occurs. --- ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs b/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs index 1f3251fd2..10435130b 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs @@ -87,7 +87,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms block.Instructions[i] = copiedExpr; } } - else if (v.IsSingleDefinition && CanPerformCopyPropagation(v, copiedExpr, splitVariables)) + else if (v.IsSingleDefinition && CanPerformCopyPropagation(v, copiedExpr, splitVariables, context.Settings)) { DoPropagate(v, copiedExpr, block, ref i, context); } @@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms } } - static bool CanPerformCopyPropagation(ILVariable target, ILInstruction value, HashSet splitVariables) + static bool CanPerformCopyPropagation(ILVariable target, ILInstruction value, HashSet splitVariables, DecompilerSettings settings) { Debug.Assert(target.StackType == value.ResultType); if (target.Type.IsSmallIntegerType()) @@ -107,14 +107,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms switch (value.OpCode) { case OpCode.LdLoca: - // case OpCode.LdElema: - // case OpCode.LdFlda: case OpCode.LdsFlda: // All address-loading instructions always return the same value for a given operand/argument combination, // so they can be safely copied. // ... except for LdElema and LdFlda, because those might throw an exception, and we don't want to // change the place where the exception is thrown. return true; + case OpCode.LdElema: + case OpCode.LdFlda: + return !settings.UseRefLocalsForAccurateOrderOfEvaluation; case OpCode.LdLoc: var v = ((LdLoc)value).Variable; if (splitVariables != null && splitVariables.Contains(v))