Browse Source

Merge branch 'master' of git://github.com/icsharpcode/ILSpy into Debugger

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
3b3c6ced71
  1. 42
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 348
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 80
      ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs
  5. 12
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  6. 1
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  7. 109
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  8. 3
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  9. 19
      ICSharpCode.Decompiler/Tests/Generics.cs
  10. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

42
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -163,8 +163,11 @@ namespace Decompiler @@ -163,8 +163,11 @@ namespace Decompiler
astType.ClassType = ClassType.Class;
}
astType.TypeParameters.AddRange(MakeTypeParameters(typeDef.GenericParameters));
astType.Constraints.AddRange(MakeConstraints(typeDef.GenericParameters));
IEnumerable<GenericParameter> genericParameters = typeDef.GenericParameters;
if (typeDef.DeclaringType != null && typeDef.DeclaringType.HasGenericParameters)
genericParameters = genericParameters.Skip(typeDef.DeclaringType.GenericParameters.Count);
astType.TypeParameters.AddRange(MakeTypeParameters(genericParameters));
astType.Constraints.AddRange(MakeConstraints(genericParameters));
// Nested types
foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
@ -268,10 +271,12 @@ namespace Decompiler @@ -268,10 +271,12 @@ namespace Decompiler
};
}
AstType baseType = ConvertType(gType.ElementType, typeAttributes, ref typeIndex);
List<AstType> typeArguments = new List<AstType>();
foreach (var typeArgument in gType.GenericArguments) {
typeIndex++;
baseType.AddChild(ConvertType(typeArgument, typeAttributes, ref typeIndex), AstType.Roles.TypeArgument);
typeArguments.Add(ConvertType(typeArgument, typeAttributes, ref typeIndex));
}
ApplyTypeArgumentsTo(baseType, typeArguments);
return baseType;
} else if (type is GenericParameter) {
return new SimpleType(type.Name);
@ -342,6 +347,30 @@ namespace Decompiler @@ -342,6 +347,30 @@ namespace Decompiler
}
}
static void ApplyTypeArgumentsTo(AstType baseType, List<AstType> typeArguments)
{
SimpleType st = baseType as SimpleType;
if (st != null) {
st.TypeArguments.AddRange(typeArguments);
}
MemberType mt = baseType as MemberType;
if (mt != null) {
TypeReference type = mt.Annotation<TypeReference>();
if (type != null) {
int typeParameterCount;
ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount);
if (typeParameterCount > typeArguments.Count)
typeParameterCount = typeArguments.Count;
mt.TypeArguments.AddRange(typeArguments.GetRange(typeArguments.Count - typeParameterCount, typeParameterCount));
typeArguments.RemoveRange(typeArguments.Count - typeParameterCount, typeParameterCount);
if (typeArguments.Count > 0)
ApplyTypeArgumentsTo(mt.Target, typeArguments);
} else {
mt.TypeArguments.AddRange(typeArguments);
}
}
}
const string DynamicAttributeFullName = "System.Runtime.CompilerServices.DynamicAttribute";
static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex)
@ -535,10 +564,13 @@ namespace Decompiler @@ -535,10 +564,13 @@ namespace Decompiler
if (gp.HasNotNullableValueTypeConstraint)
c.BaseTypes.Add(new PrimitiveType("struct"));
foreach (var constraintType in gp.Constraints)
foreach (var constraintType in gp.Constraints) {
if (gp.HasNotNullableValueTypeConstraint && constraintType.FullName == "System.ValueType")
continue;
c.BaseTypes.Add(ConvertType(constraintType));
}
if (gp.HasDefaultConstructorConstraint)
if (gp.HasDefaultConstructorConstraint && !gp.HasNotNullableValueTypeConstraint)
c.BaseTypes.Add(new PrimitiveType("new")); // new() must be last
if (c.BaseTypes.Any())
yield return c;

348
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -307,34 +307,34 @@ namespace Decompiler @@ -307,34 +307,34 @@ namespace Decompiler
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;
switch((Code)opCode) {
switch(opCode) {
#region Arithmetic
case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case Code.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case Code.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case Code.Div: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
case Code.Div_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
case Code.Mul: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case Code.Mul_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case Code.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case Code.Rem: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
case Code.Rem_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
case Code.Sub: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
case Code.Sub_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
case Code.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
case Code.And: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2);
case Code.Or: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseOr, arg2);
case Code.Xor: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2);
case Code.Shl: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2);
case Code.Shr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
case Code.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
case ILCode.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case ILCode.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case ILCode.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case ILCode.Div: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
case ILCode.Div_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
case ILCode.Mul: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case ILCode.Mul_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case ILCode.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
case ILCode.Rem: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
case ILCode.Rem_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
case ILCode.Sub: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
case ILCode.Sub_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
case ILCode.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
case ILCode.And: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2);
case ILCode.Or: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseOr, arg2);
case ILCode.Xor: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2);
case ILCode.Shl: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2);
case ILCode.Shr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
case ILCode.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
case Code.Neg: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1);
case Code.Not: return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1);
case ILCode.Neg: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1);
case ILCode.Not: return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1);
#endregion
#region Arrays
case Code.Newarr:
case (Code)ILCode.InitArray:
case ILCode.Newarr:
case ILCode.InitArray:
{
var ace = new Ast.ArrayCreateExpression();
ace.Type = operandAsTypeRef;
@ -351,39 +351,41 @@ namespace Decompiler @@ -351,39 +351,41 @@ namespace Decompiler
}
return ace;
}
case Code.Ldlen:
case ILCode.Ldlen:
return arg1.Member("Length");
case Code.Ldelem_I:
case Code.Ldelem_I1:
case Code.Ldelem_I2:
case Code.Ldelem_I4:
case Code.Ldelem_I8:
case Code.Ldelem_U1:
case Code.Ldelem_U2:
case Code.Ldelem_U4:
case Code.Ldelem_R4:
case Code.Ldelem_R8:
case Code.Ldelem_Ref:
case Code.Ldelem_Any:
case ILCode.Ldelem_I:
case ILCode.Ldelem_I1:
case ILCode.Ldelem_I2:
case ILCode.Ldelem_I4:
case ILCode.Ldelem_I8:
case ILCode.Ldelem_U1:
case ILCode.Ldelem_U2:
case ILCode.Ldelem_U4:
case ILCode.Ldelem_R4:
case ILCode.Ldelem_R8:
case ILCode.Ldelem_Ref:
case ILCode.Ldelem_Any:
return arg1.Indexer(arg2);
case Code.Ldelema:
case ILCode.Ldelema:
return MakeRef(arg1.Indexer(arg2));
case Code.Stelem_I:
case Code.Stelem_I1:
case Code.Stelem_I2:
case Code.Stelem_I4:
case Code.Stelem_I8:
case Code.Stelem_R4:
case Code.Stelem_R8:
case Code.Stelem_Ref:
case Code.Stelem_Any:
case ILCode.Stelem_I:
case ILCode.Stelem_I1:
case ILCode.Stelem_I2:
case ILCode.Stelem_I4:
case ILCode.Stelem_I8:
case ILCode.Stelem_R4:
case ILCode.Stelem_R8:
case ILCode.Stelem_Ref:
case ILCode.Stelem_Any:
return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3);
#endregion
#region Comparison
case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case Code.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Cgt_Un:
case ILCode.Ceq:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case ILCode.Cgt:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case ILCode.Cgt_Un:
// can also mean Inequality, when used with object references
{
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
@ -392,96 +394,98 @@ namespace Decompiler @@ -392,96 +394,98 @@ namespace Decompiler
else
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
}
case Code.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case ILCode.Clt:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case ILCode.Clt_Un:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
#endregion
#region Conversions
case Code.Conv_I1:
case Code.Conv_I2:
case Code.Conv_I4:
case Code.Conv_I8:
case Code.Conv_U1:
case Code.Conv_U2:
case Code.Conv_U4:
case Code.Conv_U8:
case ILCode.Conv_I1:
case ILCode.Conv_I2:
case ILCode.Conv_I4:
case ILCode.Conv_I8:
case ILCode.Conv_U1:
case ILCode.Conv_U2:
case ILCode.Conv_U4:
case ILCode.Conv_U8:
return arg1; // conversion is handled by Convert() function using the info from type analysis
case Code.Conv_I: return arg1.CastTo(typeof(IntPtr)); // TODO
case Code.Conv_U: return arg1.CastTo(typeof(UIntPtr)); // TODO
case Code.Conv_R4: return arg1.CastTo(typeof(float));
case Code.Conv_R8: return arg1.CastTo(typeof(double));
case Code.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO
case ILCode.Conv_I: return arg1.CastTo(typeof(IntPtr)); // TODO
case ILCode.Conv_U: return arg1.CastTo(typeof(UIntPtr)); // TODO
case ILCode.Conv_R4: return arg1.CastTo(typeof(float));
case ILCode.Conv_R8: return arg1.CastTo(typeof(double));
case ILCode.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO
case Code.Conv_Ovf_I1:
case Code.Conv_Ovf_I2:
case Code.Conv_Ovf_I4:
case Code.Conv_Ovf_I8:
case Code.Conv_Ovf_U1:
case Code.Conv_Ovf_U2:
case Code.Conv_Ovf_U4:
case Code.Conv_Ovf_U8:
case Code.Conv_Ovf_I1_Un:
case Code.Conv_Ovf_I2_Un:
case Code.Conv_Ovf_I4_Un:
case Code.Conv_Ovf_I8_Un:
case Code.Conv_Ovf_U1_Un:
case Code.Conv_Ovf_U2_Un:
case Code.Conv_Ovf_U4_Un:
case Code.Conv_Ovf_U8_Un:
case ILCode.Conv_Ovf_I1:
case ILCode.Conv_Ovf_I2:
case ILCode.Conv_Ovf_I4:
case ILCode.Conv_Ovf_I8:
case ILCode.Conv_Ovf_U1:
case ILCode.Conv_Ovf_U2:
case ILCode.Conv_Ovf_U4:
case ILCode.Conv_Ovf_U8:
case ILCode.Conv_Ovf_I1_Un:
case ILCode.Conv_Ovf_I2_Un:
case ILCode.Conv_Ovf_I4_Un:
case ILCode.Conv_Ovf_I8_Un:
case ILCode.Conv_Ovf_U1_Un:
case ILCode.Conv_Ovf_U2_Un:
case ILCode.Conv_Ovf_U4_Un:
case ILCode.Conv_Ovf_U8_Un:
return arg1; // conversion was handled by Convert() function using the info from type analysis
case Code.Conv_Ovf_I: return arg1.CastTo(typeof(IntPtr)); // TODO
case Code.Conv_Ovf_U: return arg1.CastTo(typeof(UIntPtr));
case Code.Conv_Ovf_I_Un: return arg1.CastTo(typeof(IntPtr));
case Code.Conv_Ovf_U_Un: return arg1.CastTo(typeof(UIntPtr));
case ILCode.Conv_Ovf_I: return arg1.CastTo(typeof(IntPtr)); // TODO
case ILCode.Conv_Ovf_U: return arg1.CastTo(typeof(UIntPtr));
case ILCode.Conv_Ovf_I_Un: return arg1.CastTo(typeof(IntPtr));
case ILCode.Conv_Ovf_U_Un: return arg1.CastTo(typeof(UIntPtr));
case Code.Castclass:
case Code.Unbox_Any:
case ILCode.Castclass:
case ILCode.Unbox_Any:
return arg1.CastTo(operandAsTypeRef);
case Code.Isinst:
case ILCode.Isinst:
return arg1.CastAs(operandAsTypeRef);
case Code.Box:
case ILCode.Box:
return arg1;
case Code.Unbox:
case ILCode.Unbox:
return InlineAssembly(byteCode, args);
#endregion
#region Indirect
case Code.Ldind_I:
case Code.Ldind_I1:
case Code.Ldind_I2:
case Code.Ldind_I4:
case Code.Ldind_I8:
case Code.Ldind_U1:
case Code.Ldind_U2:
case Code.Ldind_U4:
case Code.Ldind_R4:
case Code.Ldind_R8:
case Code.Ldind_Ref:
case Code.Ldobj:
case ILCode.Ldind_I:
case ILCode.Ldind_I1:
case ILCode.Ldind_I2:
case ILCode.Ldind_I4:
case ILCode.Ldind_I8:
case ILCode.Ldind_U1:
case ILCode.Ldind_U2:
case ILCode.Ldind_U4:
case ILCode.Ldind_R4:
case ILCode.Ldind_R8:
case ILCode.Ldind_Ref:
case ILCode.Ldobj:
if (args[0] is DirectionExpression)
return ((DirectionExpression)args[0]).Expression.Detach();
else
return InlineAssembly(byteCode, args);
case Code.Stind_I:
case Code.Stind_I1:
case Code.Stind_I2:
case Code.Stind_I4:
case Code.Stind_I8:
case Code.Stind_R4:
case Code.Stind_R8:
case Code.Stind_Ref:
case Code.Stobj:
case ILCode.Stind_I:
case ILCode.Stind_I1:
case ILCode.Stind_I2:
case ILCode.Stind_I4:
case ILCode.Stind_I8:
case ILCode.Stind_R4:
case ILCode.Stind_R8:
case ILCode.Stind_Ref:
case ILCode.Stobj:
if (args[0] is DirectionExpression)
return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), args[1]);
else
return InlineAssembly(byteCode, args);
#endregion
case Code.Arglist: return InlineAssembly(byteCode, args);
case Code.Break: return InlineAssembly(byteCode, args);
case Code.Call:
case ILCode.Arglist: return InlineAssembly(byteCode, args);
case ILCode.Break: return InlineAssembly(byteCode, args);
case ILCode.Call:
return TransformCall(false, operand, methodDef, args);
case Code.Callvirt:
case ILCode.Callvirt:
return TransformCall(true, operand, methodDef, args);
case Code.Ldftn:
case ILCode.Ldftn:
{
Cecil.MethodReference cecilMethod = ((MethodReference)operand);
var expr = new Ast.IdentifierExpression(cecilMethod.Name);
@ -490,7 +494,7 @@ namespace Decompiler @@ -490,7 +494,7 @@ namespace Decompiler
return new IdentifierExpression("ldftn").Invoke(expr)
.WithAnnotation(new Transforms.DelegateConstruction.Annotation(false));
}
case Code.Ldvirtftn:
case ILCode.Ldvirtftn:
{
Cecil.MethodReference cecilMethod = ((MethodReference)operand);
var expr = new Ast.IdentifierExpression(cecilMethod.Name);
@ -500,22 +504,23 @@ namespace Decompiler @@ -500,22 +504,23 @@ namespace Decompiler
.WithAnnotation(new Transforms.DelegateConstruction.Annotation(true));
}
case Code.Calli: return InlineAssembly(byteCode, args);
case Code.Ckfinite: return InlineAssembly(byteCode, args);
case Code.Constrained: return InlineAssembly(byteCode, args);
case Code.Cpblk: return InlineAssembly(byteCode, args);
case Code.Cpobj: return InlineAssembly(byteCode, args);
case Code.Dup: return arg1;
case Code.Endfilter: return InlineAssembly(byteCode, args);
case Code.Endfinally: return null;
case Code.Initblk: return InlineAssembly(byteCode, args);
case Code.Initobj:
case ILCode.Calli: return InlineAssembly(byteCode, args);
case ILCode.Ckfinite: return InlineAssembly(byteCode, args);
case ILCode.Constrained: return InlineAssembly(byteCode, args);
case ILCode.Cpblk: return InlineAssembly(byteCode, args);
case ILCode.Cpobj: return InlineAssembly(byteCode, args);
case ILCode.Dup: return arg1;
case ILCode.Endfilter: return InlineAssembly(byteCode, args);
case ILCode.Endfinally: return null;
case ILCode.Initblk: return InlineAssembly(byteCode, args);
case ILCode.Initobj:
if (args[0] is DirectionExpression)
return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), new DefaultValueExpression { Type = operandAsTypeRef });
else
return InlineAssembly(byteCode, args);
case Code.Jmp: return InlineAssembly(byteCode, args);
case Code.Ldarg:
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());
@ -528,59 +533,61 @@ namespace Decompiler @@ -528,59 +533,61 @@ namespace Decompiler
else
return expr;
}
case Code.Ldarga:
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 Code.Ldc_I4:
case ILCode.Ldc_I4:
return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType);
case Code.Ldc_I8:
case Code.Ldc_R4:
case Code.Ldc_R8:
case ILCode.Ldc_I8:
case ILCode.Ldc_R4:
case ILCode.Ldc_R8:
case ILCode.Ldc_Decimal:
return new Ast.PrimitiveExpression(operand);
case Code.Ldfld:
case ILCode.Ldfld:
if (arg1 is DirectionExpression)
arg1 = ((DirectionExpression)arg1).Expression.Detach();
return arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand);
case Code.Ldsfld:
case ILCode.Ldsfld:
return AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
.Member(((FieldReference)operand).Name).WithAnnotation(operand);
case Code.Stfld:
case ILCode.Stfld:
if (arg1 is DirectionExpression)
arg1 = ((DirectionExpression)arg1).Expression.Detach();
return new AssignmentExpression(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand), arg2);
case Code.Stsfld:
case ILCode.Stsfld:
return new AssignmentExpression(
AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
.Member(((FieldReference)operand).Name).WithAnnotation(operand),
arg1);
case Code.Ldflda:
case ILCode.Ldflda:
return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand));
case Code.Ldsflda:
case ILCode.Ldsflda:
return MakeRef(
AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
.Member(((FieldReference)operand).Name).WithAnnotation(operand));
case Code.Ldloc:
case ILCode.Ldloc:
localVariablesToDefine.Add((ILVariable)operand);
return new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand);
case Code.Ldloca:
case ILCode.Ldloca:
localVariablesToDefine.Add((ILVariable)operand);
return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand));
case Code.Ldnull:
case ILCode.Ldnull:
return new Ast.NullReferenceExpression();
case Code.Ldstr: return new Ast.PrimitiveExpression(operand);
case Code.Ldtoken:
case ILCode.Ldstr:
return new Ast.PrimitiveExpression(operand);
case ILCode.Ldtoken:
if (operand is Cecil.TypeReference) {
return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle");
} else {
return InlineAssembly(byteCode, args);
}
case Code.Leave: return new GotoStatement() { Label = ((ILLabel)operand).Name };
case Code.Localloc: return InlineAssembly(byteCode, args);
case Code.Mkrefany: return InlineAssembly(byteCode, args);
case Code.Newobj:
case ILCode.Leave: return new GotoStatement() { Label = ((ILLabel)operand).Name };
case ILCode.Localloc: return InlineAssembly(byteCode, args);
case ILCode.Mkrefany: return InlineAssembly(byteCode, args);
case ILCode.Newobj:
{
Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType;
@ -600,34 +607,34 @@ namespace Decompiler @@ -600,34 +607,34 @@ namespace Decompiler
oce.Arguments.AddRange(args);
return oce.WithAnnotation(operand);
}
case Code.No: return InlineAssembly(byteCode, args);
case Code.Nop: return null;
case Code.Pop: return arg1;
case Code.Readonly: return InlineAssembly(byteCode, args);
case Code.Refanytype: return InlineAssembly(byteCode, args);
case Code.Refanyval: return InlineAssembly(byteCode, args);
case Code.Ret: {
case ILCode.No: return InlineAssembly(byteCode, args);
case ILCode.Nop: return null;
case ILCode.Pop: return arg1;
case ILCode.Readonly: return InlineAssembly(byteCode, args);
case ILCode.Refanytype: return InlineAssembly(byteCode, args);
case ILCode.Refanyval: return InlineAssembly(byteCode, args);
case ILCode.Ret: {
if (methodDef.ReturnType.FullName != "System.Void") {
return new Ast.ReturnStatement { Expression = arg1 };
} else {
return new Ast.ReturnStatement();
}
}
case Code.Rethrow: return new Ast.ThrowStatement();
case Code.Sizeof:
case ILCode.Rethrow: return new Ast.ThrowStatement();
case ILCode.Sizeof:
return new Ast.SizeOfExpression { Type = operandAsTypeRef };
case Code.Starg:
case ILCode.Starg:
return new Ast.AssignmentExpression(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand), arg1);
case Code.Stloc: {
case ILCode.Stloc: {
ILVariable locVar = (ILVariable)operand;
localVariablesToDefine.Add(locVar);
return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name).WithAnnotation(locVar), arg1);
}
case Code.Switch: return InlineAssembly(byteCode, args);
case Code.Tail: return InlineAssembly(byteCode, args);
case Code.Throw: return new Ast.ThrowStatement { Expression = arg1 };
case Code.Unaligned: return InlineAssembly(byteCode, args);
case Code.Volatile: return InlineAssembly(byteCode, args);
case ILCode.Switch: return InlineAssembly(byteCode, args);
case ILCode.Tail: return InlineAssembly(byteCode, args);
case ILCode.Throw: return new Ast.ThrowStatement { Expression = arg1 };
case ILCode.Unaligned: return InlineAssembly(byteCode, args);
case ILCode.Volatile: return InlineAssembly(byteCode, args);
default: throw new Exception("Unknown OpCode: " + opCode);
}
}
@ -711,9 +718,20 @@ namespace Decompiler @@ -711,9 +718,20 @@ namespace Decompiler
}
}
// Default invocation
AdjustArgumentsForMethodCall(cecilMethod, methodArgs);
return target.Invoke(cecilMethod.Name, ConvertTypeArguments(cecilMethod), methodArgs).WithAnnotation(cecilMethod);
}
static void AdjustArgumentsForMethodCall(MethodReference cecilMethod, List<Expression> methodArgs)
{
// Convert 'ref' into 'out' where necessary
for (int i = 0; i < methodArgs.Count && i < cecilMethod.Parameters.Count; i++) {
DirectionExpression dir = methodArgs[i] as DirectionExpression;
if (dir != null && cecilMethod.Parameters[i].IsOut)
dir.FieldDirection = FieldDirection.Out;
}
}
static PropertyDefinition GetIndexer(MethodDefinition cecilMethodDef)
{
TypeDefinition typeDef = cecilMethodDef.DeclaringType;

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -96,6 +96,7 @@ @@ -96,6 +96,7 @@
<Compile Include="ILAst\ILCodes.cs" />
<Compile Include="ILAst\ILInlining.cs" />
<Compile Include="ILAst\Pattern.cs" />
<Compile Include="ILAst\PeepholeTransform.cs" />
<Compile Include="ILAst\TypeAnalysis.cs" />
<Compile Include="ITextOutput.cs" />
<Compile Include="PlainTextOutput.cs" />

80
ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs

@ -12,62 +12,52 @@ namespace Decompiler @@ -12,62 +12,52 @@ namespace Decompiler
/// <summary>
/// IL AST transformation that introduces array initializers.
/// </summary>
public class ArrayInitializers
public static class ArrayInitializers
{
public static void Transform(ILBlock method)
public static PeepholeTransform Transform(ILBlock method)
{
// TODO: move this somewhere else
// Eliminate 'dups':
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
for (int i = 0; i < expr.Arguments.Count; i++) {
if (expr.Arguments[i].Code == ILCode.Dup)
expr.Arguments[i] = expr.Arguments[i].Arguments[0];
}
}
var newArrPattern = new StoreToVariable(new ILExpression(ILCode.Newarr, ILExpression.AnyOperand, new ILExpression(ILCode.Ldc_I4, ILExpression.AnyOperand)));
var arg1 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true };
var arg2 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true };
var initializeArrayPattern = new ILCall(
"System.Runtime.CompilerServices.RuntimeHelpers", "InitializeArray",
new LoadFromVariable(arg1), new ILExpression(ILCode.Ldtoken, ILExpression.AnyOperand));
foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = block.Body.Count - 1; i >= 0; i--) {
if (!newArrPattern.Match(block.Body[i]))
continue;
ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0];
int arrayLength = (int)newArrInst.Arguments[0].Operand;
if (arrayLength == 0)
continue;
if (arg1.Match(block.Body.ElementAtOrDefault(i + 1)) && arg2.Match(block.Body.ElementAtOrDefault(i + 2))) {
if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 3))) {
if (HandleStaticallyInitializedArray(arg2, block, i, newArrInst, arrayLength)) {
i -= ILInlining.InlineInto(block, i + 1, method) - 1;
}
continue;
return delegate(ILBlock block, ref int i) {
if (!newArrPattern.Match(block.Body[i]))
return;
ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0];
int arrayLength = (int)newArrInst.Arguments[0].Operand;
if (arrayLength == 0)
return;
if (arg1.Match(block.Body.ElementAtOrDefault(i + 1)) && arg2.Match(block.Body.ElementAtOrDefault(i + 2))) {
if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 3))) {
if (HandleStaticallyInitializedArray(arg2, block, i, newArrInst, arrayLength)) {
i -= ILInlining.InlineInto(block, i + 1, method) - 1;
}
}
if (i + 1 + arrayLength > block.Body.Count)
continue;
List<ILExpression> operands = new List<ILExpression>();
for (int j = 0; j < arrayLength; j++) {
ILExpression expr = block.Body[i + 1 + j] as ILExpression;
if (expr == null || !IsStoreToArray(expr.Code))
break;
if (!(expr.Arguments[0].Code == ILCode.Ldloc && expr.Arguments[0].Operand == newArrPattern.LastVariable))
break;
if (!(expr.Arguments[1].Code == ILCode.Ldc_I4 && (int)expr.Arguments[1].Operand == j))
break;
operands.Add(expr.Arguments[2]);
}
if (operands.Count == arrayLength) {
((ILExpression)block.Body[i]).Arguments[0] = new ILExpression(
ILCode.InitArray, newArrInst.Operand, operands.ToArray());
block.Body.RemoveRange(i + 1, arrayLength);
i -= ILInlining.InlineInto(block, i + 1, method) - 1;
return;
}
}
}
if (i + 1 + arrayLength > block.Body.Count)
return;
List<ILExpression> operands = new List<ILExpression>();
for (int j = 0; j < arrayLength; j++) {
ILExpression expr = block.Body[i + 1 + j] as ILExpression;
if (expr == null || !IsStoreToArray(expr.Code))
break;
if (!(expr.Arguments[0].Code == ILCode.Ldloc && expr.Arguments[0].Operand == newArrPattern.LastVariable))
break;
if (!(expr.Arguments[1].Code == ILCode.Ldc_I4 && (int)expr.Arguments[1].Operand == j))
break;
operands.Add(expr.Arguments[2]);
}
if (operands.Count == arrayLength) {
((ILExpression)block.Body[i]).Arguments[0] = new ILExpression(
ILCode.InitArray, newArrInst.Operand, operands.ToArray());
block.Body.RemoveRange(i + 1, arrayLength);
i -= ILInlining.InlineInto(block, i + 1, method) - 1;
}
};
}
static bool IsStoreToArray(ILCode code)

12
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -19,7 +19,7 @@ namespace Decompiler.ControlFlow @@ -19,7 +19,7 @@ namespace Decompiler.ControlFlow
GotoRemoval,
DuplicateReturns,
FlattenIfStatements,
HandleArrayInitializers,
PeepholeTransforms,
TypeInference,
None
}
@ -76,8 +76,8 @@ namespace Decompiler.ControlFlow @@ -76,8 +76,8 @@ namespace Decompiler.ControlFlow
if (abortBeforeStep == ILAstOptimizationStep.FlattenIfStatements) return;
FlattenIfStatements(method);
if (abortBeforeStep == ILAstOptimizationStep.HandleArrayInitializers) return;
ArrayInitializers.Transform(method);
if (abortBeforeStep == ILAstOptimizationStep.PeepholeTransforms) return;
PeepholeTransforms.Run(context, method);
if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
TypeAnalysis.Run(context, method);
@ -562,9 +562,9 @@ namespace Decompiler.ControlFlow @@ -562,9 +562,9 @@ namespace Decompiler.ControlFlow
DefaultGoto = block.FallthoughGoto
};
result.Add(new ILBasicBlock() {
EntryLabel = block.EntryLabel, // Keep the entry label
Body = { ilSwitch }
});
EntryLabel = block.EntryLabel, // Keep the entry label
Body = { ilSwitch }
});
// Remove the item so that it is not picked up as content
if (!scope.Remove(node))

1
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -262,6 +262,7 @@ namespace Decompiler @@ -262,6 +262,7 @@ namespace Decompiler
TernaryOp, // ?:
LoopBreak,
LoopContinue,
Ldc_Decimal,
Pattern // used for ILAst pattern nodes
}

109
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -0,0 +1,109 @@ @@ -0,0 +1,109 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Linq;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
namespace Decompiler
{
public delegate void PeepholeTransform(ILBlock block, ref int i);
/// <summary>
/// Handles peephole transformations on the ILAst.
/// </summary>
public static class PeepholeTransforms
{
public static void Run(DecompilerContext context, ILBlock method)
{
PeepholeTransform[] blockTransforms = {
ArrayInitializers.Transform(method)
};
Func<ILExpression, ILExpression>[] exprTransforms = {
EliminateDups,
HandleDecimalConstants
};
// Traverse in post order so that nested blocks are transformed first. This is required so that
// patterns on the parent block can assume that all nested blocks are already transformed.
foreach (var node in TreeTraversal.PostOrder<ILNode>(method, c => c != null ? c.GetChildren() : null)) {
ILBlock block = node as ILBlock;
ILExpression expr;
if (block != null) {
// go through the instructions in reverse so that transforms can build up nested structures inside-out
for (int i = block.Body.Count - 1; i >= 0; i--) {
context.CancellationToken.ThrowIfCancellationRequested();
expr = block.Body[i] as ILExpression;
if (expr != null) {
// apply expr transforms to top-level expr in block
foreach (var t in exprTransforms)
expr = t(expr);
block.Body[i] = expr;
}
// apply block transforms
foreach (var t in blockTransforms) {
t(block, ref i);
}
}
}
expr = node as ILExpression;
if (expr != null) {
// apply expr transforms to all arguments
for (int i = 0; i < expr.Arguments.Count; i++) {
ILExpression arg = expr.Arguments[i];
foreach (var t in exprTransforms)
arg = t(arg);
expr.Arguments[i] = arg;
}
}
}
}
static ILExpression EliminateDups(ILExpression expr)
{
if (expr.Code == ILCode.Dup)
return expr.Arguments.Single();
else
return expr;
}
static ILExpression HandleDecimalConstants(ILExpression expr)
{
if (expr.Code == ILCode.Newobj) {
MethodReference r = (MethodReference)expr.Operand;
if (r.DeclaringType.Name == "Decimal" && r.DeclaringType.Namespace == "System") {
if (expr.Arguments.Count == 1) {
int? val = GetI4Constant(expr.Arguments[0]);
if (val != null) {
expr.Arguments.Clear();
expr.Code = ILCode.Ldc_Decimal;
expr.Operand = new decimal(val.Value);
expr.InferredType = r.DeclaringType;
}
} else if (expr.Arguments.Count == 5) {
int? lo = GetI4Constant(expr.Arguments[0]);
int? mid = GetI4Constant(expr.Arguments[1]);
int? hi = GetI4Constant(expr.Arguments[2]);
int? isNegative = GetI4Constant(expr.Arguments[3]);
int? scale = GetI4Constant(expr.Arguments[4]);
if (lo != null && mid != null && hi != null && isNegative != null && scale != null) {
expr.Arguments.Clear();
expr.Code = ILCode.Ldc_Decimal;
expr.Operand = new decimal(lo.Value, mid.Value, hi.Value, isNegative.Value != 0, (byte)scale);
expr.InferredType = r.DeclaringType;
}
}
}
}
return expr;
}
static int? GetI4Constant(ILExpression expr)
{
if (expr != null && expr.Code == ILCode.Ldc_I4)
return (int)expr.Operand;
else
return null;
}
}
}

3
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -303,6 +303,9 @@ namespace Decompiler @@ -303,6 +303,9 @@ namespace Decompiler
return typeSystem.Single;
case ILCode.Ldc_R8:
return typeSystem.Double;
case ILCode.Ldc_Decimal:
Debug.Assert(expr.InferredType != null && expr.InferredType.FullName == "System.Decimal");
return expr.InferredType;
case ILCode.Ldtoken:
if (expr.Operand is TypeReference)
return new TypeReference("System", "RuntimeTypeHandle", module, module, true);

19
ICSharpCode.Decompiler/Tests/Generics.cs

@ -2,11 +2,18 @@ @@ -2,11 +2,18 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
public static class Generics
{
class MyArray<T>
public class MyArray<T>
{
public class NestedClass<Y>
{
public T Item1;
public Y Item2;
}
private T[] arr;
public MyArray(int capacity)
@ -31,4 +38,14 @@ public static class Generics @@ -31,4 +38,14 @@ public static class Generics
public static void MethodWithConstraint<T, S>() where T : class, S where S : ICloneable, new()
{
}
public static void MethodWithStructConstraint<T>() where T : struct
{
}
public static Dictionary<string, string>.KeyCollection.Enumerator GetEnumerator(Dictionary<string, string> d, MyArray<string>.NestedClass<int> nc)
{
// Tests references to inner classes in generic classes
return d.Keys.GetEnumerator();
}
}

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -13,6 +13,7 @@ @@ -13,6 +13,7 @@
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<NoWarn>67,169</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PlatformTarget>x86</PlatformTarget>

Loading…
Cancel
Save