|
|
|
@ -21,6 +21,7 @@ using System.Collections.Generic;
@@ -21,6 +21,7 @@ using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics; |
|
|
|
|
using System.Linq; |
|
|
|
|
using ICSharpCode.Decompiler.TypeSystem; |
|
|
|
|
using ICSharpCode.Decompiler.Util; |
|
|
|
|
|
|
|
|
|
namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
|
{ |
|
|
|
@ -45,6 +46,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -45,6 +46,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
ILTransformContext context; |
|
|
|
|
readonly Dictionary<ILVariable, DisplayClass> displayClasses = new Dictionary<ILVariable, DisplayClass>(); |
|
|
|
|
readonly List<ILInstruction> instructionsToRemove = new List<ILInstruction>(); |
|
|
|
|
readonly MultiDictionary<IField, StObj> fieldAssignmentsWithVariableValue = new MultiDictionary<IField, StObj>(); |
|
|
|
|
|
|
|
|
|
public void Run(ILFunction function, ILTransformContext context) |
|
|
|
|
{ |
|
|
|
@ -61,10 +63,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -61,10 +63,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
continue; |
|
|
|
|
if ((context.Settings.AnonymousMethods || context.Settings.ExpressionTrees) && IsClosure(context, v, instructionsToRemove, out ITypeDefinition closureType, out var inst)) { |
|
|
|
|
AddOrUpdateDisplayClass(f, v, closureType, inst, localFunctionClosureParameter: false); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if (context.Settings.LocalFunctions && f.Kind == ILFunctionKind.LocalFunction && v.Kind == VariableKind.Parameter && v.Index > -1 && f.Method.Parameters[v.Index.Value] is IParameter p && LocalFunctionDecompiler.IsClosureParameter(p, decompilationContext)) { |
|
|
|
|
AddOrUpdateDisplayClass(f, v, ((ByReferenceType)p.Type).ElementType.GetDefinition(), f.Body, localFunctionClosureParameter: true); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
AnalyzeUseSites(v); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
VisitILFunction(function); |
|
|
|
@ -79,10 +84,35 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -79,10 +84,35 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
} finally { |
|
|
|
|
instructionsToRemove.Clear(); |
|
|
|
|
displayClasses.Clear(); |
|
|
|
|
fieldAssignmentsWithVariableValue.Clear(); |
|
|
|
|
this.context = null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void AnalyzeUseSites(ILVariable v) |
|
|
|
|
{ |
|
|
|
|
foreach (var use in v.LoadInstructions) { |
|
|
|
|
if (!(use.Parent?.Parent is Block)) |
|
|
|
|
continue; |
|
|
|
|
if (use.Parent.MatchStFld(out _, out var f, out var value) && value == use) { |
|
|
|
|
fieldAssignmentsWithVariableValue.Add(f, (StObj)use.Parent); |
|
|
|
|
} |
|
|
|
|
if (use.Parent.MatchStsFld(out f, out value) && value == use) { |
|
|
|
|
fieldAssignmentsWithVariableValue.Add(f, (StObj)use.Parent); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
foreach (var use in v.AddressInstructions) { |
|
|
|
|
if (!(use.Parent?.Parent is Block)) |
|
|
|
|
continue; |
|
|
|
|
if (use.Parent.MatchStFld(out _, out var f, out var value) && value == use) { |
|
|
|
|
fieldAssignmentsWithVariableValue.Add(f, (StObj)use.Parent); |
|
|
|
|
} |
|
|
|
|
if (use.Parent.MatchStsFld(out f, out value) && value == use) { |
|
|
|
|
fieldAssignmentsWithVariableValue.Add(f, (StObj)use.Parent); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void AddOrUpdateDisplayClass(ILFunction f, ILVariable v, ITypeDefinition closureType, ILInstruction inst, bool localFunctionClosureParameter) |
|
|
|
|
{ |
|
|
|
|
var displayClass = displayClasses.Values.FirstOrDefault(c => c.Definition == closureType); |
|
|
|
@ -110,7 +140,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -110,7 +140,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
internal static bool IsClosure(ILTransformContext context, ILVariable variable, List<ILInstruction> instructionsToRemove, out ITypeDefinition closureType, out ILInstruction initializer) |
|
|
|
|
internal static bool IsClosure(ILTransformContext context, ILVariable variable, out ITypeDefinition closureType, out ILInstruction initializer) |
|
|
|
|
{ |
|
|
|
|
return IsClosure(context, variable, instructionsToRemove: null, out closureType, out initializer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool IsClosure(ILTransformContext context, ILVariable variable, List<ILInstruction> instructionsToRemove, out ITypeDefinition closureType, out ILInstruction initializer) |
|
|
|
|
{ |
|
|
|
|
closureType = null; |
|
|
|
|
initializer = null; |
|
|
|
@ -276,18 +311,22 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -276,18 +311,22 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
protected internal override void VisitStObj(StObj inst) |
|
|
|
|
{ |
|
|
|
|
inst.Value.AcceptVisitor(this); |
|
|
|
|
if (IsParameterAssignment(inst, out var displayClass, out var field, out var parameter)) { |
|
|
|
|
context.Step($"Detected parameter assignment {parameter.Name}", inst); |
|
|
|
|
displayClass.Variables.Add((IField)field.MemberDefinition, parameter); |
|
|
|
|
instructionsToRemove.Add(inst); |
|
|
|
|
} else if (IsDisplayClassAssignment(inst, out displayClass, out field, out var variable)) { |
|
|
|
|
context.Step($"Detected display-class assignment {variable.Name}", inst); |
|
|
|
|
displayClass.Variables.Add((IField)field.MemberDefinition, variable); |
|
|
|
|
instructionsToRemove.Add(inst); |
|
|
|
|
} else { |
|
|
|
|
inst.Target.AcceptVisitor(this); |
|
|
|
|
EarlyExpressionTransforms.StObjToStLoc(inst, context); |
|
|
|
|
if (inst.Parent is Block) { |
|
|
|
|
if (IsParameterAssignment(inst, out var displayClass, out var field, out var parameter)) { |
|
|
|
|
context.Step($"Detected parameter assignment {parameter.Name}", inst); |
|
|
|
|
displayClass.Variables.Add((IField)field.MemberDefinition, parameter); |
|
|
|
|
instructionsToRemove.Add(inst); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (IsDisplayClassAssignment(inst, out displayClass, out field, out var variable)) { |
|
|
|
|
context.Step($"Detected display-class assignment {variable.Name}", inst); |
|
|
|
|
displayClass.Variables.Add((IField)field.MemberDefinition, variable); |
|
|
|
|
instructionsToRemove.Add(inst); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
inst.Target.AcceptVisitor(this); |
|
|
|
|
EarlyExpressionTransforms.StObjToStLoc(inst, context); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected internal override void VisitLdObj(LdObj inst) |
|
|
|
@ -322,6 +361,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
@@ -322,6 +361,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
|
|
|
|
|
parameter = null; |
|
|
|
|
if (!IsDisplayClassFieldAccess(inst.Target, out var displayClassVar, out displayClass, out field)) |
|
|
|
|
return false; |
|
|
|
|
if (fieldAssignmentsWithVariableValue[field].Count != 1) |
|
|
|
|
return false; |
|
|
|
|
if (!(inst.Value.MatchLdLoc(out var v) && v.Kind == VariableKind.Parameter && v.Function == currentFunction && v.Type.Equals(field.Type))) |
|
|
|
|
return false; |
|
|
|
|
if (displayClass.Variables.ContainsKey((IField)field.MemberDefinition)) |
|
|
|
|