Browse Source

Use the same representation for parameters and variables.

pull/100/head
Daniel Grunwald 16 years ago
parent
commit
01d7e2abbd
  1. 52
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 22
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  3. 9
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  4. 42
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  5. 1
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  6. 5
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  7. 20
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  8. 58
      ICSharpCode.Decompiler/ILAst/ILInlining.cs
  9. 4
      ICSharpCode.Decompiler/ILAst/PatternMatching.cs
  10. 4
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  11. 8
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  12. 52
      ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
  13. 3
      ILSpy/ILAstLanguage.cs

52
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -64,9 +64,10 @@ namespace ICSharpCode.Decompiler.Ast
bodyGraph.Optimize(context, ilMethod); bodyGraph.Optimize(context, ilMethod);
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>(e => e.Operand is ILVariable).Select(e => (ILVariable)e.Operand).Distinct(); var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
.Where(v => v != null && !v.IsParameter).Distinct();
Debug.Assert(context.CurrentMethod == methodDef); Debug.Assert(context.CurrentMethod == methodDef);
NameVariables.AssignNamesToVariables(context, allVariables, ilMethod); NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, allVariables, ilMethod);
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
Ast.BlockStatement astBlock = TransformBlock(ilMethod); Ast.BlockStatement astBlock = TransformBlock(ilMethod);
@ -401,26 +402,6 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.DefaultValue: case ILCode.DefaultValue:
return MakeDefaultValue((TypeReference)operand); return MakeDefaultValue((TypeReference)operand);
case ILCode.Jmp: return InlineAssembly(byteCode, args); case ILCode.Jmp: return InlineAssembly(byteCode, args);
case ILCode.Ldarg: {
if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
if (context.CurrentMethod.DeclaringType.IsValueType)
return MakeRef(new Ast.ThisReferenceExpression());
else
return new Ast.ThisReferenceExpression();
} else {
var expr = new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand);
if (((ParameterDefinition)operand).ParameterType is ByReferenceType)
return MakeRef(expr);
else
return expr;
}
}
case ILCode.Ldarga:
if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
return MakeRef(new Ast.ThisReferenceExpression());
} else {
return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand));
}
case ILCode.Ldc_I4: return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType); case ILCode.Ldc_I4: return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType);
case ILCode.Ldc_I8: return AstBuilder.MakePrimitive((long)operand, byteCode.InferredType); case ILCode.Ldc_I8: return AstBuilder.MakePrimitive((long)operand, byteCode.InferredType);
case ILCode.Ldc_R4: case ILCode.Ldc_R4:
@ -448,12 +429,25 @@ namespace ICSharpCode.Decompiler.Ast
return MakeRef( return MakeRef(
AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
.Member(((FieldReference)operand).Name).WithAnnotation(operand)); .Member(((FieldReference)operand).Name).WithAnnotation(operand));
case ILCode.Ldloc: case ILCode.Ldloc: {
localVariablesToDefine.Add((ILVariable)operand); ILVariable v = (ILVariable)operand;
return new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand); if (!v.IsParameter)
case ILCode.Ldloca: localVariablesToDefine.Add((ILVariable)operand);
localVariablesToDefine.Add((ILVariable)operand); Expression expr;
if (v.IsParameter && v.OriginalParameter.Index < 0)
expr = new ThisReferenceExpression();
else
expr = new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand);
return v.IsParameter && v.Type is ByReferenceType ? MakeRef(expr) : expr;
}
case ILCode.Ldloca: {
ILVariable v = (ILVariable)operand;
if (v.IsParameter && v.OriginalParameter.Index < 0)
return MakeRef(new ThisReferenceExpression());
if (!v.IsParameter)
localVariablesToDefine.Add((ILVariable)operand);
return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand)); return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand));
}
case ILCode.Ldnull: return new Ast.NullReferenceExpression(); case ILCode.Ldnull: return new Ast.NullReferenceExpression();
case ILCode.Ldstr: return new Ast.PrimitiveExpression(operand); case ILCode.Ldstr: return new Ast.PrimitiveExpression(operand);
case ILCode.Ldtoken: case ILCode.Ldtoken:
@ -497,10 +491,10 @@ namespace ICSharpCode.Decompiler.Ast
} }
case ILCode.Rethrow: return new Ast.ThrowStatement(); case ILCode.Rethrow: return new Ast.ThrowStatement();
case ILCode.Sizeof: return new Ast.SizeOfExpression { Type = operandAsTypeRef }; case ILCode.Sizeof: return new Ast.SizeOfExpression { Type = operandAsTypeRef };
case ILCode.Starg: return new Ast.AssignmentExpression(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand), arg1);
case ILCode.Stloc: { case ILCode.Stloc: {
ILVariable locVar = (ILVariable)operand; ILVariable locVar = (ILVariable)operand;
localVariablesToDefine.Add(locVar); if (!locVar.IsParameter)
localVariablesToDefine.Add(locVar);
return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name).WithAnnotation(locVar), arg1); return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name).WithAnnotation(locVar), arg1);
} }
case ILCode.Switch: return InlineAssembly(byteCode, args); case ILCode.Switch: return InlineAssembly(byteCode, args);

22
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -31,20 +31,20 @@ namespace ICSharpCode.Decompiler.Ast
}; };
public static void AssignNamesToVariables(DecompilerContext context, IEnumerable<ILVariable> variables, ILBlock methodBody) public static void AssignNamesToVariables(DecompilerContext context, IEnumerable<ILVariable> parameters, IEnumerable<ILVariable> variables, ILBlock methodBody)
{ {
NameVariables nv = new NameVariables(); NameVariables nv = new NameVariables();
nv.context = context; nv.context = context;
nv.fieldNamesInCurrentType = context.CurrentType.Fields.Select(f => f.Name).ToList(); nv.fieldNamesInCurrentType = context.CurrentType.Fields.Select(f => f.Name).ToList();
nv.AddExistingNames(context.CurrentMethod.Parameters.Select(p => p.Name)); nv.AddExistingNames(parameters.Select(p => p.Name));
nv.AddExistingNames(variables.Where(v => v.IsGenerated).Select(v => v.Name)); nv.AddExistingNames(variables.Where(v => v.IsGenerated).Select(v => v.Name));
foreach (ParameterDefinition p in context.CurrentMethod.Parameters) { foreach (ILVariable p in parameters) {
if (string.IsNullOrEmpty(p.Name)) if (string.IsNullOrEmpty(p.Name))
p.Name = nv.GenerateNameForVariableOrParameter(p, p.ParameterType, methodBody); p.Name = nv.GenerateNameForVariable(p, methodBody);
} }
foreach (ILVariable varDef in variables) { foreach (ILVariable varDef in variables) {
if (!varDef.IsGenerated) { if (!varDef.IsGenerated) {
varDef.Name = nv.GenerateNameForVariableOrParameter(varDef, varDef.Type, methodBody); varDef.Name = nv.GenerateNameForVariable(varDef, methodBody);
} }
} }
} }
@ -80,10 +80,10 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
string GenerateNameForVariableOrParameter(object variableOrParameter, TypeReference varType, ILBlock methodBody) string GenerateNameForVariable(ILVariable variable, ILBlock methodBody)
{ {
string proposedName = null; string proposedName = null;
if (varType == context.CurrentType.Module.TypeSystem.Int32) { if (variable.Type == context.CurrentType.Module.TypeSystem.Int32) {
// test whether the variable might be a loop counter // test whether the variable might be a loop counter
bool isLoopCounter = false; bool isLoopCounter = false;
foreach (ILWhileLoop loop in methodBody.GetSelfAndChildrenRecursive<ILWhileLoop>()) { foreach (ILWhileLoop loop in methodBody.GetSelfAndChildrenRecursive<ILWhileLoop>()) {
@ -97,7 +97,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Cgt: case ILCode.Cgt:
case ILCode.Cgt_Un: case ILCode.Cgt_Un:
ILVariable loadVar; ILVariable loadVar;
if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variableOrParameter) { if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) {
isLoopCounter = true; isLoopCounter = true;
} }
break; break;
@ -117,7 +117,7 @@ namespace ICSharpCode.Decompiler.Ast
if (string.IsNullOrEmpty(proposedName)) { if (string.IsNullOrEmpty(proposedName)) {
var proposedNameForStores = var proposedNameForStores =
(from expr in methodBody.GetSelfAndChildrenRecursive<ILExpression>() (from expr in methodBody.GetSelfAndChildrenRecursive<ILExpression>()
where expr.Code == ILCode.Stloc && expr.Operand == variableOrParameter where expr.Code == ILCode.Stloc && expr.Operand == variable
select GetNameFromExpression(expr.Arguments.Single()) select GetNameFromExpression(expr.Arguments.Single())
).Except(fieldNamesInCurrentType).ToList(); ).Except(fieldNamesInCurrentType).ToList();
if (proposedNameForStores.Count == 1) { if (proposedNameForStores.Count == 1) {
@ -129,7 +129,7 @@ namespace ICSharpCode.Decompiler.Ast
(from expr in methodBody.GetSelfAndChildrenRecursive<ILExpression>() (from expr in methodBody.GetSelfAndChildrenRecursive<ILExpression>()
from i in Enumerable.Range(0, expr.Arguments.Count) from i in Enumerable.Range(0, expr.Arguments.Count)
let arg = expr.Arguments[i] let arg = expr.Arguments[i]
where (arg.Code == ILCode.Ldloc || arg.Code == ILCode.Ldarg) && arg.Operand == variableOrParameter where arg.Code == ILCode.Ldloc && arg.Operand == variable
select GetNameForArgument(expr, i) select GetNameForArgument(expr, i)
).Except(fieldNamesInCurrentType).ToList(); ).Except(fieldNamesInCurrentType).ToList();
if (proposedNameForLoads.Count == 1) { if (proposedNameForLoads.Count == 1) {
@ -137,7 +137,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
if (string.IsNullOrEmpty(proposedName)) { if (string.IsNullOrEmpty(proposedName)) {
proposedName = GetNameByType(varType); proposedName = GetNameByType(variable.Type);
} }
if (!typeNames.ContainsKey(proposedName)) { if (!typeNames.ContainsKey(proposedName)) {

9
ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching; using ICSharpCode.NRefactory.CSharp.PatternMatching;
using Mono.Cecil; using Mono.Cecil;
@ -196,8 +197,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (blockStatement.Parent.NodeType == NodeType.Member || blockStatement.Parent is Accessor) { if (blockStatement.Parent.NodeType == NodeType.Member || blockStatement.Parent is Accessor) {
// Delete any following statements as long as they assign parameters to the display class // Delete any following statements as long as they assign parameters to the display class
// Do parameter handling only for closures created in the top scope (direct child of method/accessor) // Do parameter handling only for closures created in the top scope (direct child of method/accessor)
List<ParameterReference> parameterOccurrances = blockStatement.Descendants.OfType<IdentifierExpression>() List<ILVariable> parameterOccurrances = blockStatement.Descendants.OfType<IdentifierExpression>()
.Select(n => n.Annotation<ParameterReference>()).Where(p => p != null).ToList(); .Select(n => n.Annotation<ILVariable>()).Where(p => p != null && p.IsParameter).ToList();
AstNode next; AstNode next;
for (; cur != null; cur = next) { for (; cur != null; cur = next) {
next = cur.NextSibling; next = cur.NextSibling;
@ -218,8 +219,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
isParameter = true; isParameter = true;
} else if (right is IdentifierExpression) { } else if (right is IdentifierExpression) {
// handle parameters only if the whole method contains no other occurrance except for 'right' // handle parameters only if the whole method contains no other occurrance except for 'right'
ParameterReference param = right.Annotation<ParameterReference>(); ILVariable param = right.Annotation<ILVariable>();
isParameter = parameterOccurrances.Count(c => c == param) == 1; isParameter = param.IsParameter && parameterOccurrances.Count(c => c == param) == 1;
} }
if (isParameter) { if (isParameter) {
dict[m.Get<MemberReferenceExpression>("left").Single().Annotation<FieldReference>().ResolveWithinSameModule()] = right; dict[m.Get<MemberReferenceExpression>("left").Single().Annotation<FieldReference>().ResolveWithinSameModule()] = right;

42
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -450,6 +450,9 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
// Convert parameters to ILVariables
ConvertParameters(body);
return body; return body;
} }
@ -544,6 +547,45 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
public List<ILVariable> Parameters = new List<ILVariable>();
void ConvertParameters(List<ByteCode> body)
{
ILVariable thisParameter = null;
if (methodDef.HasThis) {
TypeReference type = methodDef.DeclaringType;
thisParameter = new ILVariable();
thisParameter.Type = type.IsValueType ? new ByReferenceType(type) : type;
thisParameter.Name = "this";
thisParameter.OriginalParameter = methodDef.Body.ThisParameter;
}
foreach (ParameterDefinition p in methodDef.Parameters) {
this.Parameters.Add(new ILVariable { Type = p.ParameterType, Name = p.Name, OriginalParameter = p });
}
foreach (ByteCode byteCode in body) {
ParameterDefinition p;
switch (byteCode.Code) {
case ILCode.__Ldarg:
p = (ParameterDefinition)byteCode.Operand;
byteCode.Code = ILCode.Ldloc;
byteCode.Operand = p.Index < 0 ? thisParameter : this.Parameters[p.Index];
break;
case ILCode.__Starg:
p = (ParameterDefinition)byteCode.Operand;
byteCode.Code = ILCode.Stloc;
byteCode.Operand = p.Index < 0 ? thisParameter : this.Parameters[p.Index];
break;
case ILCode.__Ldarga:
p = (ParameterDefinition)byteCode.Operand;
byteCode.Code = ILCode.Ldloca;
byteCode.Operand = p.Index < 0 ? thisParameter : this.Parameters[p.Index];
break;
}
}
if (thisParameter != null)
this.Parameters.Add(thisParameter);
}
List<ILNode> ConvertToAst(List<ByteCode> body, HashSet<ExceptionHandler> ehs) List<ILNode> ConvertToAst(List<ByteCode> body, HashSet<ExceptionHandler> ehs)
{ {
List<ILNode> ast = new List<ILNode>(); List<ILNode> ast = new List<ILNode>();

1
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -680,7 +680,6 @@ namespace ICSharpCode.Decompiler.ILAst
switch(expr.Code) { switch(expr.Code) {
case ILCode.Ldloc: case ILCode.Ldloc:
case ILCode.Ldloca: case ILCode.Ldloca:
case ILCode.Ldarg:
case ILCode.Ldstr: case ILCode.Ldstr:
case ILCode.Ldnull: case ILCode.Ldnull:
case ILCode.Ldc_I4: case ILCode.Ldc_I4:

5
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -200,6 +200,11 @@ namespace ICSharpCode.Decompiler.ILAst
public bool IsGenerated; public bool IsGenerated;
public TypeReference Type; public TypeReference Type;
public VariableDefinition OriginalVariable; public VariableDefinition OriginalVariable;
public ParameterDefinition OriginalParameter;
public bool IsParameter {
get { return OriginalParameter != null; }
}
public override string ToString() public override string ToString()
{ {

20
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -232,9 +232,9 @@ namespace ICSharpCode.Decompiler.ILAst
Clt_Un, Clt_Un,
Ldftn, Ldftn,
Ldvirtftn, Ldvirtftn,
Ldarg, __Ldarg,
Ldarga, __Ldarga,
Starg, __Starg,
Ldloc, Ldloc,
Ldloca, Ldloca,
Stloc, Stloc,
@ -375,10 +375,10 @@ namespace ICSharpCode.Decompiler.ILAst
public static void ExpandMacro(ref ILCode code, ref object operand, MethodBody methodBody) public static void ExpandMacro(ref ILCode code, ref object operand, MethodBody methodBody)
{ {
switch (code) { switch (code) {
case ILCode.__Ldarg_0: code = ILCode.Ldarg; operand = methodBody.GetParameter(0); break; case ILCode.__Ldarg_0: code = ILCode.__Ldarg; operand = methodBody.GetParameter(0); break;
case ILCode.__Ldarg_1: code = ILCode.Ldarg; operand = methodBody.GetParameter(1); break; case ILCode.__Ldarg_1: code = ILCode.__Ldarg; operand = methodBody.GetParameter(1); break;
case ILCode.__Ldarg_2: code = ILCode.Ldarg; operand = methodBody.GetParameter(2); break; case ILCode.__Ldarg_2: code = ILCode.__Ldarg; operand = methodBody.GetParameter(2); break;
case ILCode.__Ldarg_3: code = ILCode.Ldarg; operand = methodBody.GetParameter(3); break; case ILCode.__Ldarg_3: code = ILCode.__Ldarg; operand = methodBody.GetParameter(3); break;
case ILCode.__Ldloc_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break; case ILCode.__Ldloc_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break;
case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; break; case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; break;
case ILCode.__Ldloc_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break; case ILCode.__Ldloc_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break;
@ -387,9 +387,9 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; break; case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; break;
case ILCode.__Stloc_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break; case ILCode.__Stloc_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break;
case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break; case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break;
case ILCode.__Ldarg_S: code = ILCode.Ldarg; break; case ILCode.__Ldarg_S: code = ILCode.__Ldarg; break;
case ILCode.__Ldarga_S: code = ILCode.Ldarga; break; case ILCode.__Ldarga_S: code = ILCode.__Ldarga; break;
case ILCode.__Starg_S: code = ILCode.Starg; break; case ILCode.__Starg_S: code = ILCode.__Starg; break;
case ILCode.__Ldloc_S: code = ILCode.Ldloc; break; case ILCode.__Ldloc_S: code = ILCode.Ldloc; break;
case ILCode.__Ldloca_S: code = ILCode.Ldloca; break; case ILCode.__Ldloca_S: code = ILCode.Ldloca; break;
case ILCode.__Stloc_S: code = ILCode.Stloc; break; case ILCode.__Stloc_S: code = ILCode.Stloc; break;

58
ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -17,10 +17,7 @@ namespace ICSharpCode.Decompiler.ILAst
readonly ILBlock method; readonly ILBlock method;
internal Dictionary<ILVariable, int> numStloc = new Dictionary<ILVariable, int>(); internal Dictionary<ILVariable, int> numStloc = new Dictionary<ILVariable, int>();
internal Dictionary<ILVariable, int> numLdloc = new Dictionary<ILVariable, int>(); internal Dictionary<ILVariable, int> numLdloc = new Dictionary<ILVariable, int>();
Dictionary<ILVariable, int> numLdloca = new Dictionary<ILVariable, int>(); internal Dictionary<ILVariable, int> numLdloca = new Dictionary<ILVariable, int>();
Dictionary<ParameterDefinition, int> numStarg = new Dictionary<ParameterDefinition, int>();
Dictionary<ParameterDefinition, int> numLdarga = new Dictionary<ParameterDefinition, int>();
public ILInlining(ILBlock method) public ILInlining(ILBlock method)
{ {
@ -33,8 +30,6 @@ namespace ICSharpCode.Decompiler.ILAst
numStloc.Clear(); numStloc.Clear();
numLdloc.Clear(); numLdloc.Clear();
numLdloca.Clear(); numLdloca.Clear();
numStarg.Clear();
numLdarga.Clear();
// Analyse the whole method // Analyse the whole method
foreach(ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) { foreach(ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
@ -49,14 +44,6 @@ namespace ICSharpCode.Decompiler.ILAst
} else { } else {
throw new NotSupportedException(expr.Code.ToString()); throw new NotSupportedException(expr.Code.ToString());
} }
} else {
ParameterDefinition pd = expr.Operand as ParameterDefinition;
if (pd != null) {
if (expr.Code == ILCode.Starg)
numStarg[pd] = numStarg.GetOrDefault(pd) + 1;
else if (expr.Code == ILCode.Ldarga)
numLdarga[pd] = numLdarga.GetOrDefault(pd) + 1;
}
} }
} }
} }
@ -256,19 +243,7 @@ namespace ICSharpCode.Decompiler.ILAst
} }
// the expression is loading a non-forbidden variable // the expression is loading a non-forbidden variable
return true; return true;
case ILCode.Ldarg:
// Also try moving over ldarg instructions - this is necessary because an earlier copy propagation
// step might have introduced ldarg in place of an ldloc that would be skipped.
ParameterDefinition loadedParam = (ParameterDefinition)expr.Operand;
if (numLdarga.GetOrDefault(loadedParam) != 0)
return false;
foreach (ILExpression potentialStore in expressionBeingMoved.GetSelfAndChildrenRecursive<ILExpression>()) {
if (potentialStore.Code == ILCode.Starg && potentialStore.Operand == loadedParam)
return false;
}
return true;
case ILCode.Ldloca: case ILCode.Ldloca:
case ILCode.Ldarga:
case ILCode.Ldflda: case ILCode.Ldflda:
case ILCode.Ldsflda: case ILCode.Ldsflda:
case ILCode.Ldelema: case ILCode.Ldelema:
@ -290,30 +265,30 @@ namespace ICSharpCode.Decompiler.ILAst
/// 1) assignments from arguments to local variables /// 1) assignments from arguments to local variables
/// If the target variable is assigned to only once (so always is that argument) and the argument is never changed (no ldarga/starg), /// If the target variable is assigned to only once (so always is that argument) and the argument is never changed (no ldarga/starg),
/// then we can replace the variable with the argument. /// then we can replace the variable with the argument.
/// 2) assignments of 'ldloca/ldarga' to local variables /// 2) assignments of address-loading instructions to local variables
/// </summary> /// </summary>
public void CopyPropagation() public void CopyPropagation()
{ {
foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) { foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = 0; i < block.Body.Count; i++) { for (int i = 0; i < block.Body.Count; i++) {
ILVariable v; ILVariable v;
ILExpression ldArg; ILExpression copiedExpr;
if (block.Body[i].Match(ILCode.Stloc, out v, out ldArg) if (block.Body[i].Match(ILCode.Stloc, out v, out copiedExpr)
&& numStloc.GetOrDefault(v) == 1 && numLdloca.GetOrDefault(v) == 0 && !v.IsParameter && numStloc.GetOrDefault(v) == 1 && numLdloca.GetOrDefault(v) == 0
&& CanPerformCopyPropagation(ldArg)) && CanPerformCopyPropagation(copiedExpr))
{ {
// un-inline the arguments of the ldArg instruction // un-inline the arguments of the ldArg instruction
ILVariable[] uninlinedArgs = new ILVariable[ldArg.Arguments.Count]; ILVariable[] uninlinedArgs = new ILVariable[copiedExpr.Arguments.Count];
for (int j = 0; j < uninlinedArgs.Length; j++) { for (int j = 0; j < uninlinedArgs.Length; j++) {
uninlinedArgs[j] = new ILVariable { IsGenerated = true, Name = v.Name + "_cp_" + j }; uninlinedArgs[j] = new ILVariable { IsGenerated = true, Name = v.Name + "_cp_" + j };
block.Body.Insert(i++, new ILExpression(ILCode.Stloc, uninlinedArgs[j], ldArg.Arguments[j])); block.Body.Insert(i++, new ILExpression(ILCode.Stloc, uninlinedArgs[j], copiedExpr.Arguments[j]));
} }
// perform copy propagation: // perform copy propagation:
foreach (var expr in method.GetSelfAndChildrenRecursive<ILExpression>()) { foreach (var expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
if (expr.Code == ILCode.Ldloc && expr.Operand == v) { if (expr.Code == ILCode.Ldloc && expr.Operand == v) {
expr.Code = ldArg.Code; expr.Code = copiedExpr.Code;
expr.Operand = ldArg.Operand; expr.Operand = copiedExpr.Operand;
for (int j = 0; j < uninlinedArgs.Length; j++) { for (int j = 0; j < uninlinedArgs.Length; j++) {
expr.Arguments.Add(new ILExpression(ILCode.Ldloc, uninlinedArgs[j])); expr.Arguments.Add(new ILExpression(ILCode.Ldloc, uninlinedArgs[j]));
} }
@ -332,21 +307,20 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
bool CanPerformCopyPropagation(ILExpression ldArg) bool CanPerformCopyPropagation(ILExpression expr)
{ {
switch (ldArg.Code) { switch (expr.Code) {
case ILCode.Ldloca: case ILCode.Ldloca:
case ILCode.Ldarga:
case ILCode.Ldelema: case ILCode.Ldelema:
case ILCode.Ldflda: case ILCode.Ldflda:
case ILCode.Ldsflda: case ILCode.Ldsflda:
// All address-loading instructions always return the same value for a given operand/argument combination, // All address-loading instructions always return the same value for a given operand/argument combination,
// so they can be safely copied. // so they can be safely copied.
return true; return true;
case ILCode.Ldarg: case ILCode.Ldloc:
// arguments can be copied only if they aren't assigned to (directly or indirectly via ldarga) // Parameters can be copied only if they aren't assigned to (directly or indirectly via ldarga)
ParameterDefinition pd = (ParameterDefinition)ldArg.Operand; ILVariable v = (ILVariable)expr.Operand;
return numLdarga.GetOrDefault(pd) == 0 && numStarg.GetOrDefault(pd) == 0; return v.IsParameter && numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 0;
default: default:
return false; return false;
} }

4
ICSharpCode.Decompiler/ILAst/PatternMatching.cs

@ -105,8 +105,8 @@ namespace ICSharpCode.Decompiler.ILAst
public static bool MatchThis(this ILNode node) public static bool MatchThis(this ILNode node)
{ {
ParameterDefinition parDef; ILVariable v;
return node.Match(ILCode.Ldarg, out parDef) && parDef.Index == -1; return node.Match(ILCode.Ldloc, out v) && v.IsParameter && v.OriginalParameter.Index == -1;
} }
} }
} }

4
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -151,8 +151,6 @@ namespace ICSharpCode.Decompiler.ILAst
return SimplifyLdObjOrStObj(expr, ILCode.Stelem_Any); return SimplifyLdObjOrStObj(expr, ILCode.Stelem_Any);
case ILCode.Ldloca: case ILCode.Ldloca:
return SimplifyLdObjOrStObj(expr, ILCode.Stloc); return SimplifyLdObjOrStObj(expr, ILCode.Stloc);
case ILCode.Ldarga:
return SimplifyLdObjOrStObj(expr, ILCode.Starg);
case ILCode.Ldflda: case ILCode.Ldflda:
return SimplifyLdObjOrStObj(expr, ILCode.Stfld); return SimplifyLdObjOrStObj(expr, ILCode.Stfld);
case ILCode.Ldsflda: case ILCode.Ldsflda:
@ -164,8 +162,6 @@ namespace ICSharpCode.Decompiler.ILAst
return SimplifyLdObjOrStObj(expr, ILCode.Ldelem_Any); return SimplifyLdObjOrStObj(expr, ILCode.Ldelem_Any);
case ILCode.Ldloca: case ILCode.Ldloca:
return SimplifyLdObjOrStObj(expr, ILCode.Ldloc); return SimplifyLdObjOrStObj(expr, ILCode.Ldloc);
case ILCode.Ldarga:
return SimplifyLdObjOrStObj(expr, ILCode.Ldarg);
case ILCode.Ldflda: case ILCode.Ldflda:
return SimplifyLdObjOrStObj(expr, ILCode.Ldfld); return SimplifyLdObjOrStObj(expr, ILCode.Ldfld);
case ILCode.Ldsflda: case ILCode.Ldsflda:

8
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -167,16 +167,8 @@ namespace ICSharpCode.Decompiler.ILAst
} }
return v.Type; return v.Type;
} }
case ILCode.Starg:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), ((ParameterReference)expr.Operand).ParameterType);
return null;
case ILCode.Ldarg:
return ((ParameterReference)expr.Operand).ParameterType;
case ILCode.Ldloca: case ILCode.Ldloca:
return new ByReferenceType(((ILVariable)expr.Operand).Type); return new ByReferenceType(((ILVariable)expr.Operand).Type);
case ILCode.Ldarga:
return new ByReferenceType(((ParameterReference)expr.Operand).ParameterType);
#endregion #endregion
#region Call / NewObj #region Call / NewObj
case ILCode.Call: case ILCode.Call:

52
ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.ILAst
MethodDefinition disposeMethod; MethodDefinition disposeMethod;
FieldDefinition stateField; FieldDefinition stateField;
FieldDefinition currentField; FieldDefinition currentField;
Dictionary<FieldDefinition, ParameterDefinition> fieldToParameterMap = new Dictionary<FieldDefinition, ParameterDefinition>(); Dictionary<FieldDefinition, ILVariable> fieldToParameterMap = new Dictionary<FieldDefinition, ILVariable>();
List<ILNode> newBody; List<ILNode> newBody;
#region Run() method #region Run() method
@ -101,17 +101,18 @@ namespace ICSharpCode.Decompiler.ILAst
int i; int i;
for (i = 1; i < method.Body.Count; i++) { for (i = 1; i < method.Body.Count; i++) {
// stfld(..., ldloc(var_1), ldarg(...)) // stfld(..., ldloc(var_1), ldloc(parameter))
FieldReference storedField; FieldReference storedField;
ILExpression ldloc, ldarg; ILExpression ldloc, loadParameter;
if (!method.Body[i].Match(ILCode.Stfld, out storedField, out ldloc, out ldarg)) if (!method.Body[i].Match(ILCode.Stfld, out storedField, out ldloc, out loadParameter))
break; break;
if (ldloc.Code != ILCode.Ldloc || ldarg.Code != ILCode.Ldarg) ILVariable loadedVar, loadedArg;
if (!ldloc.Match(ILCode.Ldloc, out loadedVar) || !loadParameter.Match(ILCode.Ldloc, out loadedArg))
return false; return false;
storedField = GetFieldDefinition(storedField); storedField = GetFieldDefinition(storedField);
if (ldloc.Operand != var1 || storedField == null) if (loadedVar != var1 || storedField == null || !loadedArg.IsParameter)
return false; return false;
fieldToParameterMap[(FieldDefinition)storedField] = (ParameterDefinition)ldarg.Operand; fieldToParameterMap[(FieldDefinition)storedField] = loadedArg;
} }
ILVariable var2; ILVariable var2;
ILExpression ldlocForStloc2; ILExpression ldlocForStloc2;
@ -185,11 +186,11 @@ namespace ICSharpCode.Decompiler.ILAst
FieldReference field; FieldReference field;
ILExpression instExpr; ILExpression instExpr;
ILExpression stExpr; ILExpression stExpr;
ParameterDefinition arg; ILVariable arg;
if (node.Match(ILCode.Stfld, out field, out instExpr, out stExpr) && if (node.Match(ILCode.Stfld, out field, out instExpr, out stExpr) &&
instExpr.MatchThis() && instExpr.MatchThis() &&
stExpr.Match(ILCode.Ldarg, out arg) && stExpr.Match(ILCode.Ldloc, out arg) &&
arg.Index == 0) arg.IsParameter && arg.OriginalParameter.Index == 0)
{ {
stateField = GetFieldDefinition(field); stateField = GetFieldDefinition(field);
} }
@ -280,7 +281,7 @@ namespace ICSharpCode.Decompiler.ILAst
FieldDefinition storedField = GetFieldDefinition(stField); FieldDefinition storedField = GetFieldDefinition(stField);
FieldDefinition loadedField = GetFieldDefinition(ldField); FieldDefinition loadedField = GetFieldDefinition(ldField);
if (storedField != null && loadedField != null) { if (storedField != null && loadedField != null) {
ParameterDefinition mappedParameter; ILVariable mappedParameter;
if (fieldToParameterMap.TryGetValue(loadedField, out mappedParameter)) if (fieldToParameterMap.TryGetValue(loadedField, out mappedParameter))
fieldToParameterMap[storedField] = mappedParameter; fieldToParameterMap[storedField] = mappedParameter;
} }
@ -320,7 +321,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression call = finallyBody[0] as ILExpression; ILExpression call = finallyBody[0] as ILExpression;
if (call == null || call.Code != ILCode.Call || call.Arguments.Count != 1) if (call == null || call.Code != ILCode.Call || call.Arguments.Count != 1)
throw new YieldAnalysisFailedException(); throw new YieldAnalysisFailedException();
if (call.Arguments[0].Code != ILCode.Ldarg || ((ParameterDefinition)call.Arguments[0].Operand).Index >= 0) if (!call.Arguments[0].MatchThis())
throw new YieldAnalysisFailedException(); throw new YieldAnalysisFailedException();
if (!finallyBody[1].Match(ILCode.Endfinally)) if (!finallyBody[1].Match(ILCode.Endfinally))
throw new YieldAnalysisFailedException(); throw new YieldAnalysisFailedException();
@ -605,12 +606,10 @@ namespace ICSharpCode.Decompiler.ILAst
throw new YieldAnalysisFailedException(); throw new YieldAnalysisFailedException();
return new SymbolicValue(SymbolicValueType.State); return new SymbolicValue(SymbolicValueType.State);
case ILCode.Ldloc: case ILCode.Ldloc:
if (expr.Operand == rangeAnalysisStateVariable) ILVariable loadedVariable = (ILVariable)expr.Operand;
if (loadedVariable == rangeAnalysisStateVariable)
return new SymbolicValue(SymbolicValueType.State); return new SymbolicValue(SymbolicValueType.State);
else else if (loadedVariable.IsParameter && loadedVariable.OriginalParameter.Index < 0)
throw new YieldAnalysisFailedException();
case ILCode.Ldarg:
if (((ParameterDefinition)expr.Operand).Index < 0)
return new SymbolicValue(SymbolicValueType.This); return new SymbolicValue(SymbolicValueType.This);
else else
throw new YieldAnalysisFailedException(); throw new YieldAnalysisFailedException();
@ -898,11 +897,10 @@ namespace ICSharpCode.Decompiler.ILAst
switch (expr.Code) { switch (expr.Code) {
case ILCode.Ldfld: case ILCode.Ldfld:
if (expr.Arguments[0].MatchThis()) { if (expr.Arguments[0].MatchThis()) {
expr.Code = ILCode.Ldloc;
if (fieldToParameterMap.ContainsKey(field)) { if (fieldToParameterMap.ContainsKey(field)) {
expr.Code = ILCode.Ldarg;
expr.Operand = fieldToParameterMap[field]; expr.Operand = fieldToParameterMap[field];
} else { } else {
expr.Code = ILCode.Ldloc;
expr.Operand = fieldToLocalMap[field]; expr.Operand = fieldToLocalMap[field];
} }
expr.Arguments.Clear(); expr.Arguments.Clear();
@ -910,25 +908,25 @@ namespace ICSharpCode.Decompiler.ILAst
break; break;
case ILCode.Stfld: case ILCode.Stfld:
if (expr.Arguments[0].MatchThis()) { if (expr.Arguments[0].MatchThis()) {
expr.Code = ILCode.Stloc;
if (fieldToParameterMap.ContainsKey(field)) { if (fieldToParameterMap.ContainsKey(field)) {
expr.Code = ILCode.Starg;
expr.Operand = fieldToParameterMap[field]; expr.Operand = fieldToParameterMap[field];
} else { } else {
expr.Code = ILCode.Stloc;
expr.Operand = fieldToLocalMap[field]; expr.Operand = fieldToLocalMap[field];
} }
expr.Arguments.RemoveAt(0); expr.Arguments.RemoveAt(0);
} }
break; break;
case ILCode.Ldflda: case ILCode.Ldflda:
if (fieldToParameterMap.ContainsKey(field)) { if (expr.Arguments[0].MatchThis()) {
expr.Code = ILCode.Ldarga;
expr.Operand = fieldToParameterMap[field];
} else {
expr.Code = ILCode.Ldloca; expr.Code = ILCode.Ldloca;
expr.Operand = fieldToLocalMap[field]; if (fieldToParameterMap.ContainsKey(field)) {
expr.Operand = fieldToParameterMap[field];
} else {
expr.Operand = fieldToLocalMap[field];
}
expr.Arguments.Clear();
} }
expr.Arguments.Clear();
break; break;
} }
} }

3
ILSpy/ILAstLanguage.cs

@ -60,7 +60,8 @@ namespace ICSharpCode.ILSpy
new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value); new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value);
} }
var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>(e => e.Operand is ILVariable).Select(e => (ILVariable)e.Operand).Distinct(); var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
.Where(v => v != null && !v.IsParameter).Distinct();
foreach (ILVariable v in allVariables) { foreach (ILVariable v in allVariables) {
output.WriteDefinition(v.Name, v); output.WriteDefinition(v.Name, v);
if (v.Type != null) { if (v.Type != null) {

Loading…
Cancel
Save