Browse Source

Fix #1858, Fix #2188: Remove variables that contain copies of display-class variables.

pull/2426/head
Siegfried Pammer 4 years ago
parent
commit
62fc4bc1a3
  1. 24
      ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

24
ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

@ -106,6 +106,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILTransformContext context; ILTransformContext context;
ITypeResolveContext decompilationContext; ITypeResolveContext decompilationContext;
readonly Dictionary<ILVariable, DisplayClass> displayClasses = new Dictionary<ILVariable, DisplayClass>(); readonly Dictionary<ILVariable, DisplayClass> displayClasses = new Dictionary<ILVariable, DisplayClass>();
readonly Dictionary<ILVariable, ILVariable> displayClassCopyMap = new Dictionary<ILVariable, ILVariable>();
void IILTransform.Run(ILFunction function, ILTransformContext context) void IILTransform.Run(ILFunction function, ILTransformContext context)
{ {
@ -127,6 +128,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
void ClearState() void ClearState()
{ {
displayClasses.Clear(); displayClasses.Clear();
displayClassCopyMap.Clear();
this.decompilationContext = null; this.decompilationContext = null;
this.context = null; this.context = null;
} }
@ -234,6 +236,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return declaredVar.CanPropagate; return declaredVar.CanPropagate;
} }
return false; return false;
case StLoc stloc when stloc.Variable.IsSingleDefinition && stloc.Value == use:
displayClassCopyMap[stloc.Variable] = v;
return true;
default: default:
return false; 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 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 // in that case it is necessary to resolve the reference and iff it can be propagated, replace all loads
// of the single-definition. // 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 _)) if (referencedDisplayClass != null && displayClasses.TryGetValue(referencedDisplayClass, out _))
{ {
context.Step($"Propagate reference to {referencedDisplayClass.Name} in {inst.Variable}", inst); context.Step($"Propagate reference to {referencedDisplayClass.Name} in {inst.Variable}", inst);
@ -814,6 +822,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return; 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); base.VisitStObj(inst);
EarlyExpressionTransforms.StObjToStLoc(inst, context); EarlyExpressionTransforms.StObjToStLoc(inst, context);
@ -828,9 +842,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
private bool IsDisplayClassLoad(ILInstruction target, out ILVariable variable) private bool IsDisplayClassLoad(ILInstruction target, out ILVariable variable)
{ {
// We cannot use MatchLdLocRef here because local functions use ref parameters // We cannot use MatchLdLocRef here because local functions use ref parameters
if (target.MatchLdLoc(out variable) || target.MatchLdLoca(out variable)) if (!target.MatchLdLoc(out variable) && !target.MatchLdLoca(out variable))
return true;
return false; return false;
if (displayClassCopyMap.TryGetValue(variable, out ILVariable other))
variable = other;
return true;
} }
private bool IsDisplayClassFieldAccess(ILInstruction inst, private bool IsDisplayClassFieldAccess(ILInstruction inst,
@ -839,7 +855,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
displayClass = null; displayClass = null;
displayClassVar = null; displayClassVar = null;
field = null; field = null;
if (!(inst is LdFlda ldflda)) if (inst is not LdFlda ldflda)
return false; return false;
field = ldflda.Field; field = ldflda.Field;
return IsDisplayClassLoad(ldflda.Target, out displayClassVar) return IsDisplayClassLoad(ldflda.Target, out displayClassVar)

Loading…
Cancel
Save