diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs
index c8c367a40..f7df2a5d4 100644
--- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs
+++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs
@@ -1043,12 +1043,8 @@ namespace ICSharpCode.Decompiler.Ast
{
MarshalInfo marshalInfo = marshalInfoProvider.MarshalInfo;
Ast.Attribute attr = CreateNonCustomAttribute(typeof(MarshalAsAttribute), module);
- string memberName;
- if (marshalInfo.NativeType == NativeType.Boolean)
- memberName = "Bool";
- else
- memberName = marshalInfo.NativeType.ToString();
- attr.Arguments.Add(new IdentifierExpression("UnmanagedType").Member(memberName));
+ var unmanagedType = new TypeReference("System.Runtime.InteropServices", "UnmanagedType", module, module.TypeSystem.Corlib);
+ attr.Arguments.Add(MakePrimitive((int)marshalInfo.NativeType, unmanagedType));
return attr;
}
#endregion
diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
index 33786fcc2..862856915 100644
--- a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
+++ b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
@@ -40,6 +40,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
TransformAutomaticProperties(compilationUnit);
if (context.Settings.AutomaticEvents)
TransformAutomaticEvents(compilationUnit);
+
+ TransformTryCatchFinally(compilationUnit);
}
///
@@ -652,6 +654,33 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
#endregion
+ #region Try-Catch-Finally
+ static readonly TryCatchStatement tryCatchFinallyPattern = new TryCatchStatement {
+ TryBlock = new BlockStatement {
+ new TryCatchStatement {
+ TryBlock = new AnyNode(),
+ CatchClauses = { new Repeat(new AnyNode()) }
+ }
+ },
+ FinallyBlock = new AnyNode()
+ };
+
+ ///
+ /// Simplify nested 'try { try {} catch {} } finally {}'.
+ /// This transformation must run after the using/lock tranformations.
+ ///
+ void TransformTryCatchFinally(AstNode compilationUnit)
+ {
+ foreach (var tryFinally in compilationUnit.Descendants.OfType()) {
+ if (tryCatchFinallyPattern.Match(tryFinally) != null) {
+ TryCatchStatement tryCatch = (TryCatchStatement)tryFinally.TryBlock.Statements.Single();
+ tryFinally.TryBlock = tryCatch.TryBlock.Detach();
+ tryCatch.CatchClauses.MoveTo(tryFinally.CatchClauses);
+ }
+ }
+ }
+ #endregion
+
#region Pattern Matching Helpers
sealed class TypePattern : Pattern
{
diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
index 95efd0ef8..7238c15f9 100644
--- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
+++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
@@ -17,6 +17,7 @@ namespace ICSharpCode.Decompiler.ILAst
CopyPropagation,
YieldReturn,
SplitToMovableBlocks,
+ TypeInference,
PeepholeOptimizations,
FindLoops,
FindConditions,
@@ -26,7 +27,7 @@ namespace ICSharpCode.Decompiler.ILAst
FlattenIfStatements,
InlineVariables2,
PeepholeTransforms,
- TypeInference,
+ TypeInference2,
None
}
@@ -36,8 +37,12 @@ namespace ICSharpCode.Decompiler.ILAst
Dictionary labelToCfNode = new Dictionary();
+ TypeSystem typeSystem;
+
public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None)
{
+ this.typeSystem = context.CurrentMethod.Module.TypeSystem;
+
if (abortBeforeStep == ILAstOptimizationStep.SimpleGotoAndNopRemoval) return;
SimpleGotoAndNopRemoval(method);
@@ -64,10 +69,19 @@ namespace ICSharpCode.Decompiler.ILAst
SplitToBasicBlocks(block);
}
+ if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
+ // Types are needed for the ternary operator optimization
+ TypeAnalysis.Run(context, method);
+
if (abortBeforeStep == ILAstOptimizationStep.PeepholeOptimizations) return;
AnalyseLabels(method);
foreach(ILBlock block in method.GetSelfAndChildrenRecursive().ToList()) {
- PeepholeOptimizations(block);
+ bool modified;
+ do {
+ modified = false;
+ modified |= block.RunPeepholeOptimization(TrySimplifyShortCircuit);
+ modified |= block.RunPeepholeOptimization(TrySimplifyTernaryOperator);
+ } while(modified);
}
if (abortBeforeStep == ILAstOptimizationStep.FindLoops) return;
@@ -109,10 +123,15 @@ namespace ICSharpCode.Decompiler.ILAst
// open up additional inlining possibilities.
new ILInlining(method).InlineAllVariables();
+ foreach (ILExpression expr in method.GetSelfAndChildrenRecursive()) {
+ expr.InferredType = null;
+ expr.ExpectedType = null;
+ }
+
if (abortBeforeStep == ILAstOptimizationStep.PeepholeTransforms) return;
PeepholeTransforms.Run(context, method);
- if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
+ if (abortBeforeStep == ILAstOptimizationStep.TypeInference2) return;
TypeAnalysis.Run(context, method);
GotoRemoval.RemoveRedundantCode(method);
@@ -265,28 +284,8 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
- void PeepholeOptimizations(ILBlock block)
- {
- bool modified;
- do {
- modified = false;
- for (int i = 0; i < block.Body.Count;) {
- ILBasicBlock bb = (ILBasicBlock)block.Body[i];
- if (TrySimplifyShortCircuit(block.Body, bb)) {
- modified = true;
- continue;
- }
- if (TrySimplifyTernaryOperator(block.Body, bb)) {
- modified = true;
- continue;
- }
- i++;
- }
- } while(modified);
- }
-
// scope is modified if successful
- bool TrySimplifyTernaryOperator(List scope, ILBasicBlock head)
+ bool TrySimplifyTernaryOperator(List scope, ILBasicBlock head, int index)
{
Debug.Assert(scope.Contains(head));
@@ -308,8 +307,31 @@ namespace ICSharpCode.Decompiler.ILAst
trueLocVar == falseLocVar &&
trueFall == falseFall)
{
- // Create the ternary expression
- head.Body = new List() { new ILExpression(ILCode.Stloc, trueLocVar, new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr)) };
+ int boolVal;
+ ILExpression newExpr;
+ // a ? true : b is equvalent to a || b
+ // a ? b : true is equvalent to !a || b
+ // a ? b : false is equvalent to a && b
+ // a ? false : b is equvalent to !a && b
+ if (trueLocVar.Type == typeSystem.Boolean && trueExpr.Match(ILCode.Ldc_I4, out boolVal)) {
+ // It can be expressed as logical expression
+ if (boolVal != 0) {
+ newExpr = new ILExpression(ILCode.LogicOr, null, condExpr, falseExpr);
+ } else {
+ newExpr = new ILExpression(ILCode.LogicAnd, null, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr);
+ }
+ } else if (trueLocVar.Type == typeSystem.Boolean && falseExpr.Match(ILCode.Ldc_I4, out boolVal)) {
+ // It can be expressed as logical expression
+ if (boolVal != 0) {
+ newExpr = new ILExpression(ILCode.LogicOr, null, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr);
+ } else {
+ newExpr = new ILExpression(ILCode.LogicAnd, null, condExpr, trueExpr);
+ }
+ } else {
+ // Create ternary expression
+ newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr);
+ }
+ head.Body = new List() { new ILExpression(ILCode.Stloc, trueLocVar, newExpr) };
head.FallthoughGoto = new ILExpression(ILCode.Br, trueFall);
// Remove the old basic blocks
@@ -326,7 +348,7 @@ namespace ICSharpCode.Decompiler.ILAst
}
// scope is modified if successful
- bool TrySimplifyShortCircuit(List scope, ILBasicBlock head)
+ bool TrySimplifyShortCircuit(List scope, ILBasicBlock head, int index)
{
Debug.Assert(scope.Contains(head));
@@ -977,6 +999,25 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
+ ///
+ /// Perform one pass of a given optimization on this block.
+ /// This block must consist of only basicblocks.
+ ///
+ public static bool RunPeepholeOptimization(this ILBlock block, Func, ILBasicBlock, int, bool> optimization)
+ {
+ bool modified = false;
+ List body = block.Body;
+ for (int i = 0; i < body.Count;) {
+ if (optimization(body, (ILBasicBlock)body[i], i)) {
+ modified = true;
+ i = Math.Max(0, i - 1); // Go back one step
+ } else {
+ i++;
+ }
+ }
+ return modified;
+ }
+
public static bool CanFallThough(this ILNode node)
{
ILExpression expr = node as ILExpression;
diff --git a/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs b/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs
index 21b259126..65717b2bb 100644
--- a/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs
+++ b/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs
@@ -22,4 +22,28 @@ public class ExceptionHandling
throw;
}
}
+
+ public void TryCatchFinally()
+ {
+ try {
+ Console.WriteLine("Try");
+ } catch (Exception ex) {
+ Console.WriteLine(ex.Message);
+ } finally {
+ Console.WriteLine("Finally");
+ }
+ }
+
+ public void TryCatchMultipleHandlers()
+ {
+ try {
+ Console.WriteLine("Try");
+ } catch (InvalidOperationException ex) {
+ Console.WriteLine(ex.Message);
+ } catch (Exception ex) {
+ Console.WriteLine(ex.Message);
+ } catch {
+ Console.WriteLine("other");
+ }
+ }
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Match.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Match.cs
index 9b1ff905f..5e76a428c 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Match.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Match.cs
@@ -12,6 +12,8 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
///
public sealed class Match
{
+ // TODO: maybe we should add an implicit Match->bool conversion? (operator implicit bool(Match m) { return m != null; })
+
List> results = new List>();
internal int CheckPoint()
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs
index aa8d95fb7..6d893b58c 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs
@@ -79,6 +79,11 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
return p != null ? new SwitchSectionPlaceholder(p) : null;
}
+ public static implicit operator CatchClause(Pattern p)
+ {
+ return p != null ? new CatchClausePlaceholder(p) : null;
+ }
+
// Make debugging easier by giving Patterns a ToString() implementation
public override string ToString()
{
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs
index 2e3c2b592..b30ca58f2 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs
@@ -210,4 +210,33 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
return child.DoMatchCollection(role, pos, match, backtrackingStack);
}
}
+
+ sealed class CatchClausePlaceholder : CatchClause
+ {
+ readonly AstNode child;
+
+ public CatchClausePlaceholder(AstNode child)
+ {
+ this.child = child;
+ }
+
+ public override NodeType NodeType {
+ get { return NodeType.Placeholder; }
+ }
+
+ public override S AcceptVisitor(IAstVisitor visitor, T data)
+ {
+ return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, child, data);
+ }
+
+ protected internal override bool DoMatch(AstNode other, Match match)
+ {
+ return child.DoMatch(other, match);
+ }
+
+ internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack)
+ {
+ return child.DoMatchCollection(role, pos, match, backtrackingStack);
+ }
+ }
}