diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs index a6d649756..9a622432d 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs @@ -106,6 +106,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms ILTransformContext context; ITypeResolveContext decompilationContext; readonly Dictionary displayClasses = new Dictionary(); + readonly Dictionary displayClassCopyMap = new Dictionary(); void IILTransform.Run(ILFunction function, ILTransformContext context) { @@ -127,6 +128,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms void ClearState() { displayClasses.Clear(); + displayClassCopyMap.Clear(); this.decompilationContext = null; this.context = null; } @@ -234,6 +236,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms return declaredVar.CanPropagate; } return false; + case StLoc stloc when stloc.Variable.IsSingleDefinition && stloc.Value == use: + displayClassCopyMap[stloc.Variable] = v; + return true; default: return false; } @@ -784,7 +789,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms // in some cases (e.g. if inlining fails), there can be a reference to a display class in a stack slot, // in that case it is necessary to resolve the reference and iff it can be propagated, replace all loads // of the single-definition. - var referencedDisplayClass = ResolveVariableToPropagate(inst.Value); + if (!displayClassCopyMap.TryGetValue(inst.Variable, out var referencedDisplayClass)) + { + referencedDisplayClass = ResolveVariableToPropagate(inst.Value); + } if (referencedDisplayClass != null && displayClasses.TryGetValue(referencedDisplayClass, out _)) { context.Step($"Propagate reference to {referencedDisplayClass.Name} in {inst.Variable}", inst); @@ -814,6 +822,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms return; } } + if (inst.Value is LdLoc ldLoc && ldLoc.Variable is { IsSingleDefinition: true, CaptureScope: null } + && ldLoc.Variable.StoreInstructions.FirstOrDefault() is StLoc stloc + && stloc.Parent is Block block) + { + ILInlining.InlineOneIfPossible(block, stloc.ChildIndex, InliningOptions.None, context); + } } base.VisitStObj(inst); EarlyExpressionTransforms.StObjToStLoc(inst, context); @@ -828,9 +842,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms private bool IsDisplayClassLoad(ILInstruction target, out ILVariable variable) { // We cannot use MatchLdLocRef here because local functions use ref parameters - if (target.MatchLdLoc(out variable) || target.MatchLdLoca(out variable)) - return true; - return false; + if (!target.MatchLdLoc(out variable) && !target.MatchLdLoca(out variable)) + return false; + if (displayClassCopyMap.TryGetValue(variable, out ILVariable other)) + variable = other; + return true; } private bool IsDisplayClassFieldAccess(ILInstruction inst, @@ -839,7 +855,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms displayClass = null; displayClassVar = null; field = null; - if (!(inst is LdFlda ldflda)) + if (inst is not LdFlda ldflda) return false; field = ldflda.Field; return IsDisplayClassLoad(ldflda.Target, out displayClassVar)