Browse Source

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.
null-coalescing-assignment
Daniel Grunwald 4 months ago
parent
commit
c84605a610
  1. 9
      ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs

9
ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs

@ -87,7 +87,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -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 @@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
static bool CanPerformCopyPropagation(ILVariable target, ILInstruction value, HashSet<ILVariable> splitVariables)
static bool CanPerformCopyPropagation(ILVariable target, ILInstruction value, HashSet<ILVariable> splitVariables, DecompilerSettings settings)
{
Debug.Assert(target.StackType == value.ResultType);
if (target.Type.IsSmallIntegerType())
@ -107,14 +107,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -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))

Loading…
Cancel
Save