From 986e5e06cc2426c6e10b86f860a423c8bb677ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Sat, 19 Feb 2011 12:28:58 +0000 Subject: [PATCH] Proper support for catch block argument --- .../Ast/AstMethodBodyBuilder.cs | 2 +- ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs | 59 ++++++++++++++----- ICSharpCode.Decompiler/ILAst/ILAstTypes.cs | 1 + ICSharpCode.Decompiler/ILAst/ILCodes.cs | 3 +- 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 5dfecb27b..769c1367c 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -206,7 +206,7 @@ namespace Decompiler tryCatchStmt.CatchClauses.Add( new Ast.CatchClause { Type = AstBuilder.ConvertType(catchClause.ExceptionType), - VariableName = "exception", + VariableName = catchClause.ExceptionVariable == null ? null : catchClause.ExceptionVariable.Name, Body = TransformBlock(catchClause) }); } diff --git a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs index 22c340a1d..e8a219e67 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs @@ -93,6 +93,9 @@ namespace Decompiler Dictionary instrToByteCode = new Dictionary(); Dictionary allowInline = new Dictionary(); + // Virtual instructions to load exception on stack + Dictionary ldexceptions = new Dictionary(); + public List Variables; public List Build(MethodDefinition methodDef, bool optimize) @@ -147,7 +150,14 @@ namespace Decompiler ByteCode handlerStart = instrToByteCode[ex.HandlerType == ExceptionHandlerType.Filter ? ex.FilterStart : ex.HandlerStart]; handlerStart.StackBefore = new List(); if (ex.HandlerType == ExceptionHandlerType.Catch || ex.HandlerType == ExceptionHandlerType.Filter) { - handlerStart.StackBefore.Add(new StackSlot(null)); + ByteCode ldexception = new ByteCode() { + Code = ILCode.Ldexception, + Operand = ex.CatchType, + PopCount = 0, + PushCount = 1 + }; + ldexceptions[ex] = ldexception; + handlerStart.StackBefore.Add(new StackSlot(ldexception)); } agenda.Enqueue(handlerStart); @@ -231,13 +241,10 @@ namespace Decompiler ILVariable tmpVar = new ILVariable() { Name = string.Format("arg_{0:X2}_{1}", byteCode.Offset, argIdx), IsGenerated = true }; arg.LoadFrom = tmpVar; foreach(ByteCode pushedBy in arg.PushedBy) { - // TODO: Handle exception variables - if (pushedBy != null) { - if (pushedBy.StoreTo == null) { - pushedBy.StoreTo = new List(1); - } - pushedBy.StoreTo.Add(tmpVar); + if (pushedBy.StoreTo == null) { + pushedBy.StoreTo = new List(1); } + pushedBy.StoreTo.Add(tmpVar); } if (arg.PushedBy.Count == 1) { allowInline[tmpVar] = true; @@ -329,12 +336,38 @@ namespace Decompiler ehs.ExceptWith(nestedEHs); List handlerAst = ConvertToAst(body.CutRange(startIndex, count), nestedEHs); if (eh.HandlerType == ExceptionHandlerType.Catch) { - tryCatchBlock.CatchBlocks.Add(new ILTryCatchBlock.CatchBlock() { + ILTryCatchBlock.CatchBlock catchBlock = new ILTryCatchBlock.CatchBlock() { ExceptionType = eh.CatchType, Body = handlerAst - }); + }; + // Handle the automatically pushed exception on the stack + ByteCode ldexception = ldexceptions[eh]; + if (ldexception.StoreTo.Count == 0) { + throw new Exception("Exception should be consumed by something"); + } else if (ldexception.StoreTo.Count == 1) { + ILExpression first = catchBlock.Body[0] as ILExpression; + if (first != null && + first.Code == ILCode.Pop && + first.Arguments[0].Code == ILCode.Ldloc && + first.Arguments[0].Operand == ldexception.StoreTo[0]) + { + // The exception is just poped - optimize it all away; + catchBlock.ExceptionVariable = null; + catchBlock.Body.RemoveAt(0); + } else { + catchBlock.ExceptionVariable = ldexception.StoreTo[0]; + } + } else { + ILVariable exTemp = new ILVariable() { Name = "ex_" + eh.HandlerStart.Offset.ToString("X2"), IsGenerated = true }; + catchBlock.ExceptionVariable = exTemp; + foreach(ILVariable storeTo in ldexception.StoreTo) { + catchBlock.Body.Insert(0, new ILExpression(ILCode.Stloc, storeTo, new ILExpression(ILCode.Ldloc, exTemp))); + } + } + tryCatchBlock.CatchBlocks.Add(catchBlock); } else if (eh.HandlerType == ExceptionHandlerType.Finally) { tryCatchBlock.FinallyBlock = new ILBlock(handlerAst); + // TODO: ldexception } else { // TODO } @@ -369,13 +402,7 @@ namespace Decompiler int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count; for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) { StackSlot slot = byteCode.StackBefore[i]; - if (slot.PushedBy != null) { - ILExpression ldExpr = new ILExpression(ILCode.Ldloc, slot.LoadFrom); - expr.Arguments.Add(ldExpr); - } else { - ILExpression ldExpr = new ILExpression(ILCode.Ldloc, new ILVariable() { Name = "ex", IsGenerated = true }); - expr.Arguments.Add(ldExpr); - } + expr.Arguments.Add(new ILExpression(ILCode.Ldloc, slot.LoadFrom)); } // Store the result to temporary variable(s) if needed diff --git a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs index 81341dbbd..143548b6d 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs @@ -88,6 +88,7 @@ namespace Decompiler public class CatchBlock: ILBlock { public TypeReference ExceptionType; + public ILVariable ExceptionVariable; public override void WriteTo(ITextOutput output) { diff --git a/ICSharpCode.Decompiler/ILAst/ILCodes.cs b/ICSharpCode.Decompiler/ILAst/ILCodes.cs index 62d7a1169..7cb0abec5 100644 --- a/ICSharpCode.Decompiler/ILAst/ILCodes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILCodes.cs @@ -253,7 +253,8 @@ namespace Decompiler Refanytype, Readonly, - // Virtual codes - defined for convenience + // Virtual codes - defined for convenience + Ldexception, // Operand holds the CatchType for catch handler, null for filter } public static class ILCodeUtil