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
private static Expression ConvertArgumentValue(CustomAttributeArgument parameter) private static Expression ConvertArgumentValue(CustomAttributeArgument parameter)
{ {
var type = parameter.Type.Resolve(); var type = parameter.Type.Resolve();
Expression parameterValue; if (type != null && type.IsEnum) {
if (type.IsEnum) return MakePrimitive(Convert.ToInt64(parameter.Value), type);
{ } else if (parameter.Value is TypeReference) {
parameterValue = MakePrimitive(Convert.ToInt64(parameter.Value), type); return new TypeOfExpression() {
}
else if (parameter.Value is TypeReference)
{
parameterValue = new TypeOfExpression()
{
Type = ConvertType((TypeReference)parameter.Value), Type = ConvertType((TypeReference)parameter.Value),
}; };
} else {
return new PrimitiveExpression(parameter.Value);
} }
else
{
parameterValue = new PrimitiveExpression(parameter.Value);
}
return parameterValue;
} }
#endregion #endregion

121
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -113,7 +113,7 @@ namespace ICSharpCode.Decompiler.Ast
} else if (node is ILWhileLoop) { } else if (node is ILWhileLoop) {
ILWhileLoop ilLoop = (ILWhileLoop)node; ILWhileLoop ilLoop = (ILWhileLoop)node;
WhileStatement whileStmt = new WhileStatement() { 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) EmbeddedStatement = TransformBlock(ilLoop.BodyBlock)
}; };
yield return whileStmt; yield return whileStmt;
@ -121,7 +121,7 @@ namespace ICSharpCode.Decompiler.Ast
ILCondition conditionalNode = (ILCondition)node; ILCondition conditionalNode = (ILCondition)node;
bool hasFalseBlock = conditionalNode.FalseBlock.EntryGoto != null || conditionalNode.FalseBlock.Body.Count > 0; bool hasFalseBlock = conditionalNode.FalseBlock.EntryGoto != null || conditionalNode.FalseBlock.Body.Count > 0;
yield return new Ast.IfElseStatement { yield return new Ast.IfElseStatement {
Condition = MakeBranchCondition(conditionalNode.Condition), Condition = (Expression)TransformExpression(conditionalNode.Condition),
TrueStatement = TransformBlock(conditionalNode.TrueBlock), TrueStatement = TransformBlock(conditionalNode.TrueBlock),
FalseStatement = hasFalseBlock ? TransformBlock(conditionalNode.FalseBlock) : null FalseStatement = hasFalseBlock ? TransformBlock(conditionalNode.FalseBlock) : null
}; };
@ -171,61 +171,6 @@ namespace ICSharpCode.Decompiler.Ast
return args; 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) static string FormatByteCodeOperand(object operand)
{ {
if (operand == null) { if (operand == null) {
@ -263,53 +208,15 @@ namespace ICSharpCode.Decompiler.Ast
AstNode TransformByteCode(ILExpression byteCode) AstNode TransformByteCode(ILExpression byteCode)
{ {
ILCode opCode = byteCode.Code;
object operand = byteCode.Operand; object operand = byteCode.Operand;
AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference); 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); List<Ast.Expression> args = TransformExpressionArguments(byteCode);
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
Ast.Expression arg3 = args.Count >= 3 ? args[2] : null; Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;
switch(opCode) { switch(byteCode.Code) {
#region Arithmetic #region Arithmetic
case ILCode.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, 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: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@ -345,7 +252,7 @@ namespace ICSharpCode.Decompiler.Ast
// change "new (int[,])[10] to new int[10][,]" // change "new (int[,])[10] to new int[10][,]"
ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
} }
if (opCode == ILCode.InitArray) { if (byteCode.Code == ILCode.InitArray) {
ace.Initializer = new ArrayInitializerExpression(); ace.Initializer = new ArrayInitializerExpression();
ace.Initializer.Elements.AddRange(args); ace.Initializer.Elements.AddRange(args);
} else { } else {
@ -400,6 +307,24 @@ namespace ICSharpCode.Decompiler.Ast
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case ILCode.Clt_Un: case ILCode.Clt_Un:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); 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 #endregion
#region Conversions #region Conversions
case ILCode.Conv_I1: case ILCode.Conv_I1:
@ -637,7 +562,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Throw: return new Ast.ThrowStatement { Expression = arg1 }; case ILCode.Throw: return new Ast.ThrowStatement { Expression = arg1 };
case ILCode.Unaligned: return InlineAssembly(byteCode, args); case ILCode.Unaligned: return InlineAssembly(byteCode, args);
case ILCode.Volatile: 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 @@
using System; using System;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms namespace ICSharpCode.Decompiler.Ast.Transforms
@ -32,26 +33,91 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return null; return null;
// Move arguments from invocation to initializer: // Move arguments from invocation to initializer:
invocation.Arguments.MoveTo(ci.Arguments); invocation.Arguments.MoveTo(ci.Arguments);
// Add the initializer: // Add the initializer: (unless it is the default 'base()')
constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation<MethodReference>()); if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0))
constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation<MethodReference>());
// Remove the statement: // Remove the statement:
stmt.Remove(); stmt.Remove();
} }
return null; 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) 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); base.VisitTypeDeclaration(typeDeclaration, data);
// Remove single empty constructor: // Remove single empty constructor:
var ctors = typeDeclaration.Members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray(); if (instanceCtors.Length == 1) {
if (ctors.Length == 1 && ctors[0].Body.Children.Count() == 0 ConstructorDeclaration emptyCtor = new ConstructorDeclaration();
&& ctors[0].Initializer.ConstructorInitializerType == ConstructorInitializerType.Base emptyCtor.Modifiers = ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public);
&& ctors[0].Initializer.Arguments.Count() == 0 emptyCtor.Body = new BlockStatement();
&& ctors[0].Parameters.Count == 0 if (emptyCtor.Match(instanceCtors[0]) != null)
&& ctors[0].Modifiers == ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public)) instanceCtors[0].Remove();
{ }
ctors[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; return null;
} }

6
ICSharpCode.Decompiler/ILAst/GotoRemoval.cs

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

264
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

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

52
ICSharpCode.Decompiler/ILAst/ILCodes.cs

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

19
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.ILAst
#region CachedDelegateInitialization #region CachedDelegateInitialization
void CachedDelegateInitialization(ILBlock block, ref int i) void CachedDelegateInitialization(ILBlock block, ref int i)
{ {
// if (logicnot(brtrue(ldsfld(field)))) { // if (logicnot(ldsfld(field))) {
// stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method))) // stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method)))
// } else { // } else {
// } // }
@ -134,7 +134,9 @@ namespace ICSharpCode.Decompiler.ILAst
return; return;
if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0)) if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0))
return; 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) if (condition == null || condition.Code != ILCode.Ldsfld)
return; return;
FieldDefinition field = condition.Operand as FieldDefinition; // field is defined in current assembly FieldDefinition field = condition.Operand as FieldDefinition; // field is defined in current assembly
@ -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 #endregion
} }
} }

34
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -39,6 +39,14 @@ namespace ICSharpCode.Decompiler.ILAst
void InferTypes(ILNode node) 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; ILExpression expr = node as ILExpression;
if (expr != null) { if (expr != null) {
ILVariable v = expr.Operand as ILVariable; ILVariable v = expr.Operand as ILVariable;
@ -111,13 +119,13 @@ namespace ICSharpCode.Decompiler.ILAst
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
} }
return typeSystem.Boolean; return typeSystem.Boolean;
case ILCode.BrLogicAnd: case ILCode.LogicAnd:
case ILCode.BrLogicOr: case ILCode.LogicOr:
if (forceInferChildren) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean);
} }
return null; return typeSystem.Boolean;
case ILCode.TernaryOp: case ILCode.TernaryOp:
if (forceInferChildren) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
@ -438,30 +446,10 @@ namespace ICSharpCode.Decompiler.ILAst
return typeSystem.Boolean; return typeSystem.Boolean;
#endregion #endregion
#region Branch instructions #region Branch instructions
case ILCode.Beq:
case ILCode.Bne_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, null);
return null;
case ILCode.Brtrue: case ILCode.Brtrue:
case ILCode.Brfalse:
if (forceInferChildren) if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
return null; 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.Br:
case ILCode.Leave: case ILCode.Leave:
case ILCode.Endfinally: case ILCode.Endfinally:

Loading…
Cancel
Save