Browse Source

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

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
90fd8ee8ff
  1. 20
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 121
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 86
      ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
  4. 6
      ICSharpCode.Decompiler/ILAst/GotoRemoval.cs
  5. 264
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  6. 8
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  7. 52
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  8. 19
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  9. 34
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

20
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -981,23 +981,15 @@ namespace ICSharpCode.Decompiler.Ast @@ -981,23 +981,15 @@ namespace ICSharpCode.Decompiler.Ast
private static Expression ConvertArgumentValue(CustomAttributeArgument parameter)
{
var type = parameter.Type.Resolve();
Expression parameterValue;
if (type.IsEnum)
{
parameterValue = MakePrimitive(Convert.ToInt64(parameter.Value), type);
}
else if (parameter.Value is TypeReference)
{
parameterValue = new TypeOfExpression()
{
if (type != null && type.IsEnum) {
return MakePrimitive(Convert.ToInt64(parameter.Value), type);
} else if (parameter.Value is TypeReference) {
return new TypeOfExpression() {
Type = ConvertType((TypeReference)parameter.Value),
};
} else {
return new PrimitiveExpression(parameter.Value);
}
else
{
parameterValue = new PrimitiveExpression(parameter.Value);
}
return parameterValue;
}
#endregion

121
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -113,7 +113,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -113,7 +113,7 @@ namespace ICSharpCode.Decompiler.Ast
} else if (node is ILWhileLoop) {
ILWhileLoop ilLoop = (ILWhileLoop)node;
WhileStatement whileStmt = new WhileStatement() {
Condition = ilLoop.Condition != null ? MakeBranchCondition(ilLoop.Condition) : new PrimitiveExpression(true),
Condition = ilLoop.Condition != null ? (Expression)TransformExpression(ilLoop.Condition) : new PrimitiveExpression(true),
EmbeddedStatement = TransformBlock(ilLoop.BodyBlock)
};
yield return whileStmt;
@ -121,7 +121,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -121,7 +121,7 @@ namespace ICSharpCode.Decompiler.Ast
ILCondition conditionalNode = (ILCondition)node;
bool hasFalseBlock = conditionalNode.FalseBlock.EntryGoto != null || conditionalNode.FalseBlock.Body.Count > 0;
yield return new Ast.IfElseStatement {
Condition = MakeBranchCondition(conditionalNode.Condition),
Condition = (Expression)TransformExpression(conditionalNode.Condition),
TrueStatement = TransformBlock(conditionalNode.TrueBlock),
FalseStatement = hasFalseBlock ? TransformBlock(conditionalNode.FalseBlock) : null
};
@ -171,61 +171,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -171,61 +171,6 @@ namespace ICSharpCode.Decompiler.Ast
return args;
}
Ast.Expression MakeBranchCondition(ILExpression expr)
{
// get IL Ranges for expression
var ilRanges = expr.GetILRanges();
switch(expr.Code) {
case ILCode.LogicNot:
return (new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, MakeBranchCondition(expr.Arguments[0]))).WithAnnotation(ilRanges);
case ILCode.BrLogicAnd:
return (new Ast.BinaryOperatorExpression(
MakeBranchCondition(expr.Arguments[0]),
BinaryOperatorType.ConditionalAnd,
MakeBranchCondition(expr.Arguments[1]))
).WithAnnotation(ilRanges);
case ILCode.BrLogicOr:
return (new Ast.BinaryOperatorExpression(
MakeBranchCondition(expr.Arguments[0]),
BinaryOperatorType.ConditionalOr,
MakeBranchCondition(expr.Arguments[1])
)).WithAnnotation(ilRanges);
}
List<Ast.Expression> args = TransformExpressionArguments(expr);
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
switch((Code)expr.Code) {
case Code.Brfalse:
return (new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1)).WithAnnotation(ilRanges);
case Code.Brtrue:
return arg1.WithAnnotation(ilRanges);
case Code.Beq:
return (new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2)).WithAnnotation(ilRanges);
case Code.Bge:
return (new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2)).WithAnnotation(ilRanges);
case Code.Bge_Un:
return (new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2)).WithAnnotation(ilRanges);
case Code.Bgt:
return (new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2)).WithAnnotation(ilRanges);
case Code.Bgt_Un:
return (new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2)).WithAnnotation(ilRanges);
case Code.Ble:
return (new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2)).WithAnnotation(ilRanges);
case Code.Ble_Un:
return (new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2)).WithAnnotation(ilRanges);
case Code.Blt:
return (new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2)).WithAnnotation(ilRanges);
case Code.Blt_Un:
return (new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2)).WithAnnotation(ilRanges);
case Code.Bne_Un:
return (new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2)).WithAnnotation(ilRanges);
default:
throw new Exception("Bad opcode");
}
}
static string FormatByteCodeOperand(object operand)
{
if (operand == null) {
@ -263,53 +208,15 @@ namespace ICSharpCode.Decompiler.Ast @@ -263,53 +208,15 @@ namespace ICSharpCode.Decompiler.Ast
AstNode TransformByteCode(ILExpression byteCode)
{
ILCode opCode = byteCode.Code;
object operand = byteCode.Operand;
AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference);
ILExpression operandAsByteCode = operand as ILExpression;
// Do branches first because TransformExpressionArguments does not work on arguments that are branches themselfs
// TODO: We should probably have virtual instructions for these and not abuse branch codes as expressions
switch(opCode) {
case ILCode.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
case ILCode.Brfalse:
case ILCode.Brtrue:
case ILCode.Beq:
case ILCode.Bge:
case ILCode.Bge_Un:
case ILCode.Bgt:
case ILCode.Bgt_Un:
case ILCode.Ble:
case ILCode.Ble_Un:
case ILCode.Blt:
case ILCode.Blt_Un:
case ILCode.Bne_Un:
case ILCode.BrLogicAnd:
case ILCode.BrLogicOr:
return new Ast.IfElseStatement() {
Condition = MakeBranchCondition(byteCode),
TrueStatement = new BlockStatement() {
new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name)
}
};
case ILCode.TernaryOp:
return new Ast.ConditionalExpression() {
Condition = MakeBranchCondition(byteCode.Arguments[0]),
TrueExpression = (Expression)TransformExpression(byteCode.Arguments[1]),
FalseExpression = (Expression)TransformExpression(byteCode.Arguments[2]),
};
case ILCode.LoopBreak:
return new Ast.BreakStatement();
case ILCode.LoopContinue:
return new Ast.ContinueStatement();
}
List<Ast.Expression> args = TransformExpressionArguments(byteCode);
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;
switch(opCode) {
switch(byteCode.Code) {
#region Arithmetic
case ILCode.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case ILCode.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@ -345,7 +252,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -345,7 +252,7 @@ namespace ICSharpCode.Decompiler.Ast
// change "new (int[,])[10] to new int[10][,]"
ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
}
if (opCode == ILCode.InitArray) {
if (byteCode.Code == ILCode.InitArray) {
ace.Initializer = new ArrayInitializerExpression();
ace.Initializer.Elements.AddRange(args);
} else {
@ -400,6 +307,24 @@ namespace ICSharpCode.Decompiler.Ast @@ -400,6 +307,24 @@ namespace ICSharpCode.Decompiler.Ast
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case ILCode.Clt_Un:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
#endregion
#region Logical
case ILCode.LogicNot: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
case ILCode.LogicAnd: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalAnd, arg2);
case ILCode.LogicOr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalOr, arg2);
case ILCode.TernaryOp: return new Ast.ConditionalExpression() { Condition = arg1, TrueExpression = arg2, FalseExpression = arg3 };
#endregion
#region Branch
case ILCode.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
case ILCode.Brtrue:
return new Ast.IfElseStatement() {
Condition = arg1,
TrueStatement = new BlockStatement() {
new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name)
}
};
case ILCode.LoopBreak: return new Ast.BreakStatement();
case ILCode.LoopContinue: return new Ast.ContinueStatement();
#endregion
#region Conversions
case ILCode.Conv_I1:
@ -637,7 +562,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -637,7 +562,7 @@ namespace ICSharpCode.Decompiler.Ast
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);
default: throw new Exception("Unknown OpCode: " + byteCode.Code);
}
}

86
ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
using System;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms
@ -32,26 +33,91 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -32,26 +33,91 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return null;
// Move arguments from invocation to initializer:
invocation.Arguments.MoveTo(ci.Arguments);
// Add the initializer:
constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation<MethodReference>());
// Add the initializer: (unless it is the default 'base()')
if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0))
constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation<MethodReference>());
// Remove the statement:
stmt.Remove();
}
return null;
}
static readonly ExpressionStatement fieldInitializerPattern = new ExpressionStatement {
Expression = new AssignmentExpression {
Left = new NamedNode("fieldAccess", new MemberReferenceExpression { Target = new ThisReferenceExpression() }),
Operator = AssignmentOperatorType.Assign,
Right = new AnyNode("initializer")
}
};
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
var instanceCtors = typeDeclaration.Members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
if (instanceCtors.Length > 0 && typeDeclaration.ClassType == NRefactory.TypeSystem.ClassType.Class) {
// Recognize field initializers:
// Convert first statement in all ctors (if all ctors have the same statement) into a field initializer.
bool allSame;
do {
Match m = fieldInitializerPattern.Match(instanceCtors[0].Body.FirstOrDefault());
if (m == null)
break;
FieldDefinition fieldDef = m.Get("fieldAccess").Single().Annotation<FieldDefinition>();
if (fieldDef == null)
break;
FieldDeclaration fieldDecl = typeDeclaration.Members.OfType<FieldDeclaration>().FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
if (fieldDecl == null)
break;
allSame = true;
for (int i = 1; i < instanceCtors.Length; i++) {
if (instanceCtors[0].Body.First().Match(instanceCtors[i].Body.FirstOrDefault()) == null)
allSame = false;
}
if (allSame) {
foreach (var ctor in instanceCtors)
ctor.Body.First().Remove();
fieldDecl.Variables.Single().Initializer = m.Get<Expression>("initializer").Single().Detach();
}
} while (allSame);
}
// Now convert base constructor calls to initializers:
base.VisitTypeDeclaration(typeDeclaration, data);
// Remove single empty constructor:
var ctors = typeDeclaration.Members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
if (ctors.Length == 1 && ctors[0].Body.Children.Count() == 0
&& ctors[0].Initializer.ConstructorInitializerType == ConstructorInitializerType.Base
&& ctors[0].Initializer.Arguments.Count() == 0
&& ctors[0].Parameters.Count == 0
&& ctors[0].Modifiers == ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public))
{
ctors[0].Remove();
if (instanceCtors.Length == 1) {
ConstructorDeclaration emptyCtor = new ConstructorDeclaration();
emptyCtor.Modifiers = ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public);
emptyCtor.Body = new BlockStatement();
if (emptyCtor.Match(instanceCtors[0]) != null)
instanceCtors[0].Remove();
}
// Convert static constructor into field initializers if the class is BeforeFieldInit
var staticCtor = typeDeclaration.Members.OfType<ConstructorDeclaration>().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static);
if (staticCtor != null) {
TypeDefinition typeDef = typeDeclaration.Annotation<TypeDefinition>();
if (typeDef != null && typeDef.IsBeforeFieldInit) {
while (true) {
ExpressionStatement es = staticCtor.Body.Statements.FirstOrDefault() as ExpressionStatement;
if (es == null)
break;
AssignmentExpression assignment = es.Expression as AssignmentExpression;
if (assignment == null || assignment.Operator != AssignmentOperatorType.Assign)
break;
FieldDefinition fieldDef = assignment.Left.Annotation<FieldDefinition>();
if (fieldDef == null || !fieldDef.IsStatic)
break;
FieldDeclaration fieldDecl = typeDeclaration.Members.OfType<FieldDeclaration>().FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
if (fieldDecl == null)
break;
fieldDecl.Variables.Single().Initializer = assignment.Right.Detach();
es.Remove();
}
if (staticCtor.Body.Statements.Count == 0)
staticCtor.Remove();
}
}
return null;
}

6
ICSharpCode.Decompiler/ILAst/GotoRemoval.cs

@ -68,7 +68,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -68,7 +68,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (target == null)
return false;
if (target == Exit(gotoExpr, new HashSet<ILNode>())) {
if (target == Exit(gotoExpr, new HashSet<ILNode>() { gotoExpr })) {
gotoExpr.Code = ILCode.Nop;
gotoExpr.Operand = null;
target.ILRanges.AddRange(gotoExpr.ILRanges);
@ -83,13 +83,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -83,13 +83,13 @@ namespace ICSharpCode.Decompiler.ILAst
loop = current as ILWhileLoop;
}
if (loop != null && target == Exit(loop, new HashSet<ILNode>())) {
if (loop != null && target == Exit(loop, new HashSet<ILNode>() { gotoExpr })) {
gotoExpr.Code = ILCode.LoopBreak;
gotoExpr.Operand = null;
return true;
}
if (loop != null && target == Enter(loop, new HashSet<ILNode>())) {
if (loop != null && target == Enter(loop, new HashSet<ILNode>() { gotoExpr })) {
gotoExpr.Code = ILCode.LoopContinue;
gotoExpr.Operand = null;
return true;

264
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -11,6 +11,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -11,6 +11,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
public enum ILAstOptimizationStep
{
ReduceBranchInstructionSet,
SplitToMovableBlocks,
PeepholeOptimizations,
FindLoops,
@ -32,6 +33,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -32,6 +33,11 @@ namespace ICSharpCode.Decompiler.ILAst
public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None)
{
if (abortBeforeStep == ILAstOptimizationStep.ReduceBranchInstructionSet) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
ReduceBranchInstructionSet(block);
}
if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
SplitToBasicBlocks(block);
@ -85,6 +91,39 @@ namespace ICSharpCode.Decompiler.ILAst @@ -85,6 +91,39 @@ namespace ICSharpCode.Decompiler.ILAst
GotoRemoval.RemoveRedundantCode(method);
}
/// <summary>
/// Reduces the branch codes to just br and brtrue.
/// Moves ILRanges to the branch argument
/// </summary>
void ReduceBranchInstructionSet(ILBlock block)
{
for (int i = 0; i < block.Body.Count; i++) {
ILExpression expr = block.Body[i] as ILExpression;
if (expr != null && expr.Prefixes == null) {
switch(expr.Code) {
case ILCode.Brtrue:
expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges);
expr.ILRanges.Clear();
continue;
case ILCode.__Brfalse: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, expr.Arguments.Single())); break;
case ILCode.__Beq: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Ceq, null, expr.Arguments)); break;
case ILCode.__Bne_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Ceq, null, expr.Arguments))); break;
case ILCode.__Bgt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt, null, expr.Arguments)); break;
case ILCode.__Bgt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments)); break;
case ILCode.__Ble: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt, null, expr.Arguments))); break;
case ILCode.__Ble_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments))); break;
case ILCode.__Blt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt, null, expr.Arguments)); break;
case ILCode.__Blt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt_Un, null, expr.Arguments)); break;
case ILCode.__Bge: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt, null, expr.Arguments))); break;
case ILCode.__Bge_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt_Un, null, expr.Arguments))); break;
default:
continue;
}
((ILExpression)block.Body[i]).Arguments.Single().ILRanges.AddRange(expr.ILRanges);
}
}
}
/// <summary>
/// Group input into a set of blocks that can be later arbitraliby schufled.
/// The method adds necessary branches to make control flow between blocks
@ -196,31 +235,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -196,31 +235,11 @@ namespace ICSharpCode.Decompiler.ILAst
} while(modified);
}
bool IsConditionalBranch(ILBasicBlock bb, ref ILExpression branchExpr, ref ILLabel trueLabel, ref ILLabel falseLabel)
{
if (bb.Body.Count == 1) {
branchExpr = bb.Body[0] as ILExpression;
if (branchExpr != null &&
branchExpr.Operand is ILLabel &&
branchExpr.Arguments.Count > 0 &&
branchExpr.Prefixes == null)
{
trueLabel = (ILLabel)branchExpr.Operand;
falseLabel = (ILLabel)((ILExpression)bb.FallthoughGoto).Operand;
return true;
}
}
return false;
}
bool IsStloc(ILBasicBlock bb, ref ILVariable locVar, ref ILExpression val, ref ILLabel fallLabel)
{
if (bb.Body.Count == 1) {
ILExpression expr = bb.Body[0] as ILExpression;
if (expr != null &&
expr.Code == ILCode.Stloc &&
expr.Prefixes == null)
{
ILExpression expr;
if (bb.Body[0].Match(ILCode.Stloc, out expr)) {
locVar = (ILVariable)expr.Operand;
val = expr.Arguments[0];
fallLabel = (ILLabel)bb.FallthoughGoto.Operand;
@ -235,7 +254,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -235,7 +254,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
Debug.Assert(scope.Contains(head));
ILExpression branchExpr = null;
ILExpression condExpr = null;
ILLabel trueLabel = null;
ILLabel falseLabel = null;
ILVariable trueLocVar = null;
@ -245,7 +264,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -245,7 +264,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression falseExpr = null;
ILLabel falseFall = null;
if(IsConditionalBranch(head, ref branchExpr, ref trueLabel, ref falseLabel) &&
if(head.MatchBrTure(out condExpr, out trueLabel, out falseLabel) &&
labelGlobalRefCount[trueLabel] == 1 &&
labelGlobalRefCount[falseLabel] == 1 &&
IsStloc(labelToBasicBlock[trueLabel], ref trueLocVar, ref trueExpr, ref trueFall) &&
@ -254,24 +273,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -254,24 +273,16 @@ namespace ICSharpCode.Decompiler.ILAst
trueFall == falseFall)
{
// Create the ternary expression
head.Body = new List<ILNode>() {
new ILExpression(ILCode.Stloc, trueLocVar,
new ILExpression(ILCode.TernaryOp, null,
new ILExpression(branchExpr.Code, null, branchExpr.Arguments.ToArray()),
trueExpr,
falseExpr
)
)
};
head.Body = new List<ILNode>() { new ILExpression(ILCode.Stloc, trueLocVar, new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr)) };
head.FallthoughGoto = new ILExpression(ILCode.Br, trueFall);
// Remove the old basic blocks
scope.Remove(labelToBasicBlock[trueLabel]);
scope.Remove(labelToBasicBlock[falseLabel]);
labelToBasicBlock.Remove(trueLabel);
labelToBasicBlock.Remove(falseLabel);
labelGlobalRefCount.Remove(trueLabel);
labelGlobalRefCount.Remove(falseLabel);
scope.RemoveOrThrow(labelToBasicBlock[trueLabel]);
scope.RemoveOrThrow(labelToBasicBlock[falseLabel]);
labelToBasicBlock.RemoveOrThrow(trueLabel);
labelToBasicBlock.RemoveOrThrow(falseLabel);
labelGlobalRefCount.RemoveOrThrow(trueLabel);
labelGlobalRefCount.RemoveOrThrow(falseLabel);
return true;
}
@ -283,10 +294,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -283,10 +294,10 @@ namespace ICSharpCode.Decompiler.ILAst
{
Debug.Assert(scope.Contains(head));
ILExpression branchExpr = null;
ILLabel trueLabel = null;
ILLabel falseLabel = null;
if(IsConditionalBranch(head, ref branchExpr, ref trueLabel, ref falseLabel)) {
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(head.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) {
for (int pass = 0; pass < 2; pass++) {
// On the second pass, swap labels and negate expression of the first branch
@ -296,32 +307,27 @@ namespace ICSharpCode.Decompiler.ILAst @@ -296,32 +307,27 @@ namespace ICSharpCode.Decompiler.ILAst
bool negate = (pass == 1);
ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel];
ILExpression nextBranchExpr = null;
ILLabel nextTrueLablel = null;
ILLabel nextFalseLabel = null;
ILExpression nextCondExpr;
ILLabel nextTrueLablel;
ILLabel nextFalseLabel;
if (scope.Contains(nextBasicBlock) &&
nextBasicBlock != head &&
labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 &&
IsConditionalBranch(nextBasicBlock, ref nextBranchExpr, ref nextTrueLablel, ref nextFalseLabel) &&
nextBasicBlock.MatchBrTure(out nextCondExpr, out nextTrueLablel, out nextFalseLabel) &&
(otherLablel == nextFalseLabel || otherLablel == nextTrueLablel))
{
// We are using the branches as expressions now, so do not keep their labels alive
branchExpr.Operand = null;
nextBranchExpr.Operand = null;
// Create short cicuit branch
if (otherLablel == nextFalseLabel) {
head.Body[0] = new ILExpression(ILCode.BrLogicAnd, nextTrueLablel, negate ? new ILExpression(ILCode.LogicNot, null, branchExpr) : branchExpr, nextBranchExpr);
head.Body[0] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicAnd, null, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr));
} else {
head.Body[0] = new ILExpression(ILCode.BrLogicOr, nextTrueLablel, negate ? branchExpr : new ILExpression(ILCode.LogicNot, null, branchExpr), nextBranchExpr);
head.Body[0] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicOr, null, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr));
}
head.FallthoughGoto = new ILExpression(ILCode.Br, nextFalseLabel);
// Remove the inlined branch from scope
labelGlobalRefCount.Remove(nextBasicBlock.EntryLabel);
labelToBasicBlock.Remove(nextBasicBlock.EntryLabel);
if (!scope.Remove(nextBasicBlock))
throw new Exception("Element not found");
labelGlobalRefCount.RemoveOrThrow(nextBasicBlock.EntryLabel);
labelToBasicBlock.RemoveOrThrow(nextBasicBlock.EntryLabel);
scope.RemoveOrThrow(nextBasicBlock);
return true;
}
@ -448,48 +454,71 @@ namespace ICSharpCode.Decompiler.ILAst @@ -448,48 +454,71 @@ namespace ICSharpCode.Decompiler.ILAst
while(agenda.Count > 0) {
ControlFlowNode node = agenda.Dequeue();
// If the node is a loop header
if (scope.Contains(node)
&& node.DominanceFrontier.Contains(node)
&& (node != entryPoint || !excludeEntryPoint))
{
HashSet<ControlFlowNode> loopContents = FindLoopContent(scope, node);
// If the first expression is a loop condition
ILBasicBlock basicBlock = (ILBasicBlock)node.UserData;
ILExpression branchExpr = null;
ILLabel trueLabel = null;
ILLabel falseLabel = null;
if(IsConditionalBranch(basicBlock, ref branchExpr, ref trueLabel, ref falseLabel)) {
loopContents.Remove(node);
scope.Remove(node);
branchExpr.Operand = null; // Do not keep label alive
// TODO: Does 'true' really point into the loop body? Swap if necessary
ControlFlowNode postLoopTarget;
labelToCfNode.TryGetValue(falseLabel, out postLoopTarget);
if (postLoopTarget != null) {
// Pull more nodes into the loop
HashSet<ControlFlowNode> postLoopContents = FindDominatedNodes(scope, postLoopTarget);
var pullIn = scope.Except(postLoopContents).Where(n => node.Dominates(n));
loopContents.UnionWith(pullIn);
}
// Use loop to implement the condition
result.Add(new ILBasicBlock() {
EntryLabel = basicBlock.EntryLabel,
Body = new List<ILNode>() {
new ILWhileLoop() {
Condition = branchExpr,
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, trueLabel),
Body = FindLoops(loopContents, node, true)
}
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(basicBlock.MatchBrTure(out condExpr, out trueLabel, out falseLabel))
{
ControlFlowNode trueTarget;
labelToCfNode.TryGetValue(trueLabel, out trueTarget);
ControlFlowNode falseTarget;
labelToCfNode.TryGetValue(falseLabel, out falseTarget);
// If one point inside the loop and the other outside
if ((!loopContents.Contains(trueTarget) && loopContents.Contains(falseTarget)) ||
(loopContents.Contains(trueTarget) && !loopContents.Contains(falseTarget)) )
{
loopContents.RemoveOrThrow(node);
scope.RemoveOrThrow(node);
// If false means enter the loop
if (loopContents.Contains(falseTarget))
{
// Negate the condition
condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
ILLabel tmp = trueLabel;
trueLabel = falseLabel;
falseLabel = tmp;
}
ControlFlowNode postLoopTarget;
labelToCfNode.TryGetValue(falseLabel, out postLoopTarget);
if (postLoopTarget != null) {
// Pull more nodes into the loop
HashSet<ControlFlowNode> postLoopContents = FindDominatedNodes(scope, postLoopTarget);
var pullIn = scope.Except(postLoopContents).Where(n => node.Dominates(n));
loopContents.UnionWith(pullIn);
}
// Use loop to implement the condition
result.Add(new ILBasicBlock() {
EntryLabel = basicBlock.EntryLabel,
Body = new List<ILNode>() {
new ILWhileLoop() {
Condition = condExpr,
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, trueLabel),
Body = FindLoops(loopContents, node, true)
}
},
new ILExpression(ILCode.Br, falseLabel)
},
new ILExpression(ILCode.Br, falseLabel)
},
FallthoughGoto = null
});
} else {
FallthoughGoto = null
});
}
}
// Fallback method: while(true)
if (scope.Contains(node)) {
result.Add(new ILBasicBlock() {
EntryLabel = new ILLabel() { Name = "Loop_" + (nextLabelIndex++) },
Body = new List<ILNode>() {
@ -567,8 +596,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -567,8 +596,7 @@ namespace ICSharpCode.Decompiler.ILAst
});
// Remove the item so that it is not picked up as content
if (!scope.Remove(node))
throw new Exception("Item is not in set");
scope.RemoveOrThrow(node);
// Pull in code of cases
ControlFlowNode fallTarget = null;
@ -602,23 +630,20 @@ namespace ICSharpCode.Decompiler.ILAst @@ -602,23 +630,20 @@ namespace ICSharpCode.Decompiler.ILAst
}
// Two-way branch
ILExpression branchExpr = null;
ILLabel trueLabel = null;
ILLabel falseLabel = null;
if(IsConditionalBranch(block, ref branchExpr, ref trueLabel, ref falseLabel)) {
// The branch label will not be used - kill it
branchExpr.Operand = null;
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(block.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) {
// Swap bodies since that seems to be the usual C# order
ILLabel temp = trueLabel;
trueLabel = falseLabel;
falseLabel = temp;
branchExpr = new ILExpression(ILCode.LogicNot, null, branchExpr);
condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
// Convert the basic block to ILCondition
ILCondition ilCond = new ILCondition() {
Condition = branchExpr,
Condition = condExpr,
TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) },
FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) }
};
@ -628,8 +653,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -628,8 +653,7 @@ namespace ICSharpCode.Decompiler.ILAst
});
// Remove the item immediately so that it is not picked up as content
if (!scope.Remove(node))
throw new Exception("Item is not in set");
scope.RemoveOrThrow(node);
ControlFlowNode trueTarget = null;
labelToCfNode.TryGetValue(trueLabel, out trueTarget);
@ -811,10 +835,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -811,10 +835,24 @@ namespace ICSharpCode.Decompiler.ILAst
if (expr != null && expr.Prefixes == null && expr.Code == code) {
operand = (T)expr.Operand;
return true;
} else {
operand = default(T);
return false;
}
operand = default(T);
return false;
}
public static bool MatchBrTure(this ILBasicBlock bb, out ILExpression condition, out ILLabel trueLabel, out ILLabel falseLabel)
{
if (bb.Body.Count == 1) {
if (bb.Body[0].Match(ILCode.Brtrue, out trueLabel)) {
condition = ((ILExpression)bb.Body[0]).Arguments.Single();
falseLabel = (ILLabel)((ILExpression)bb.FallthoughGoto).Operand;
return true;
}
}
condition = null;
trueLabel = null;
falseLabel = null;
return false;
}
public static bool CanFallthough(this ILNode node)
@ -833,5 +871,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -833,5 +871,17 @@ namespace ICSharpCode.Decompiler.ILAst
}
return true;
}
public static void RemoveOrThrow<T>(this ICollection<T> collection, T item)
{
if (!collection.Remove(item))
throw new Exception("The item was not found in the collection");
}
public static void RemoveOrThrow<K,V>(this Dictionary<K,V> collection, K key)
{
if (!collection.Remove(key))
throw new Exception("The key was not found in the dictionary");
}
}
}

8
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -220,6 +220,14 @@ namespace ICSharpCode.Decompiler.ILAst @@ -220,6 +220,14 @@ namespace ICSharpCode.Decompiler.ILAst
public static readonly object AnyOperand = new object();
public ILExpression(ILCode code, object operand, List<ILExpression> args)
{
this.Code = code;
this.Operand = operand;
this.Arguments = new List<ILExpression>(args);
this.ILRanges = new List<ILRange>(1);
}
public ILExpression(ILCode code, object operand, params ILExpression[] args)
{
this.Code = code;

52
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler.ILAst
public enum ILCode
{
// For convenience, the start is exactly identical to Mono.Cecil.Cil.Code
// The macro instructions should never be used and are therefore prepended by __
// Instructions that should not be used are prepended by __
Nop,
Break,
__Ldarg_0,
@ -89,18 +89,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -89,18 +89,18 @@ namespace ICSharpCode.Decompiler.ILAst
__Ble_Un_S,
__Blt_Un_S,
Br,
Brfalse,
__Brfalse,
Brtrue,
Beq,
Bge,
Bgt,
Ble,
Blt,
Bne_Un,
Bge_Un,
Bgt_Un,
Ble_Un,
Blt_Un,
__Beq,
__Bge,
__Bgt,
__Ble,
__Blt,
__Bne_Un,
__Bge_Un,
__Bgt_Un,
__Ble_Un,
__Blt_Un,
Switch,
Ldind_I1,
Ldind_U1,
@ -256,8 +256,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -256,8 +256,8 @@ namespace ICSharpCode.Decompiler.ILAst
// Virtual codes - defined for convenience
Ldexception, // Operand holds the CatchType for catch handler, null for filter
LogicNot,
BrLogicAnd,
BrLogicOr,
LogicAnd,
LogicOr,
InitArray, // Array Initializer
TernaryOp, // ?:
LoopBreak,
@ -271,7 +271,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -271,7 +271,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
public static string GetName(this ILCode code)
{
return code.ToString().ToLowerInvariant().Replace('_','.');
return code.ToString().ToLowerInvariant().TrimStart('_').Replace('_','.');
}
public static bool CanFallThough(this ILCode code)
@ -396,18 +396,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -396,18 +396,18 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break;
case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break;
case ILCode.__Br_S: code = ILCode.Br; break;
case ILCode.__Brfalse_S: code = ILCode.Brfalse; break;
case ILCode.__Brfalse_S: code = ILCode.__Brfalse; break;
case ILCode.__Brtrue_S: code = ILCode.Brtrue; break;
case ILCode.__Beq_S: code = ILCode.Beq; break;
case ILCode.__Bge_S: code = ILCode.Bge; break;
case ILCode.__Bgt_S: code = ILCode.Bgt; break;
case ILCode.__Ble_S: code = ILCode.Ble; break;
case ILCode.__Blt_S: code = ILCode.Blt; break;
case ILCode.__Bne_Un_S: code = ILCode.Bne_Un; break;
case ILCode.__Bge_Un_S: code = ILCode.Bge_Un; break;
case ILCode.__Bgt_Un_S: code = ILCode.Bgt_Un; break;
case ILCode.__Ble_Un_S: code = ILCode.Ble_Un; break;
case ILCode.__Blt_Un_S: code = ILCode.Blt_Un; break;
case ILCode.__Beq_S: code = ILCode.__Beq; break;
case ILCode.__Bge_S: code = ILCode.__Bge; break;
case ILCode.__Bgt_S: code = ILCode.__Bgt; break;
case ILCode.__Ble_S: code = ILCode.__Ble; break;
case ILCode.__Blt_S: code = ILCode.__Blt; break;
case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break;
case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break;
case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break;
case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break;
case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break;
case ILCode.__Leave_S: code = ILCode.Leave; break;
}
}

19
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.ILAst
#region CachedDelegateInitialization
void CachedDelegateInitialization(ILBlock block, ref int i)
{
// if (logicnot(brtrue(ldsfld(field)))) {
// if (logicnot(ldsfld(field))) {
// stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method)))
// } else {
// }
@ -134,7 +134,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -134,7 +134,9 @@ namespace ICSharpCode.Decompiler.ILAst
return;
if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0))
return;
ILExpression condition = UnpackBrFalse(c.Condition);
if (!c.Condition.Match(ILCode.LogicNot))
return;
ILExpression condition = c.Condition.Arguments.Single() as ILExpression;
if (condition == null || condition.Code != ILCode.Ldsfld)
return;
FieldDefinition field = condition.Operand as FieldDefinition; // field is defined in current assembly
@ -168,19 +170,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -168,19 +170,6 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
}
/// <summary>
/// Returns 'result' in brfalse(result) or logicnot(brtrue(result)).
/// </summary>
static ILExpression UnpackBrFalse(ILExpression condition)
{
if (condition.Code == ILCode.Brfalse) {
return condition.Arguments.Single();
} else if (condition.Code == ILCode.LogicNot && condition.Arguments.Single().Code == ILCode.Brtrue) {
return condition.Arguments.Single().Arguments.Single();
}
return null;
}
#endregion
}
}

34
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -39,6 +39,14 @@ namespace ICSharpCode.Decompiler.ILAst @@ -39,6 +39,14 @@ namespace ICSharpCode.Decompiler.ILAst
void InferTypes(ILNode node)
{
ILCondition cond = node as ILCondition;
if (cond != null) {
InferTypeForExpression(cond.Condition, typeSystem.Boolean, false);
}
ILWhileLoop loop = node as ILWhileLoop;
if (loop != null && loop.Condition != null) {
InferTypeForExpression(loop.Condition, typeSystem.Boolean, false);
}
ILExpression expr = node as ILExpression;
if (expr != null) {
ILVariable v = expr.Operand as ILVariable;
@ -111,13 +119,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -111,13 +119,13 @@ namespace ICSharpCode.Decompiler.ILAst
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
}
return typeSystem.Boolean;
case ILCode.BrLogicAnd:
case ILCode.BrLogicOr:
case ILCode.LogicAnd:
case ILCode.LogicOr:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean);
}
return null;
return typeSystem.Boolean;
case ILCode.TernaryOp:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
@ -438,30 +446,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -438,30 +446,10 @@ namespace ICSharpCode.Decompiler.ILAst
return typeSystem.Boolean;
#endregion
#region Branch instructions
case ILCode.Beq:
case ILCode.Bne_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, null);
return null;
case ILCode.Brtrue:
case ILCode.Brfalse:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
return null;
case ILCode.Blt:
case ILCode.Ble:
case ILCode.Bgt:
case ILCode.Bge:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, true);
return null;
case ILCode.Blt_Un:
case ILCode.Ble_Un:
case ILCode.Bgt_Un:
case ILCode.Bge_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, false);
return null;
case ILCode.Br:
case ILCode.Leave:
case ILCode.Endfinally:

Loading…
Cancel
Save