From c1fb133fd3804822949e2a70a1fc8582fe41fcec Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 8 Jun 2014 15:53:43 +0200 Subject: [PATCH] Fix AsyncDecompiler for roslyn-compiled methods that have finally blocks. --- .../ILAst/AsyncDecompiler.cs | 61 +++++++++++++++---- .../ILAst/PatternMatching.cs | 6 ++ 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs b/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs index a8eb43f6f..0c8bb8b99 100644 --- a/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs +++ b/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs @@ -333,7 +333,7 @@ namespace ICSharpCode.Decompiler.ILAst bool MatchStateAssignment(ILNode stfld, out int stateID) { - // stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(-2)) + // stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(stateId)) stateID = 0; FieldReference fieldRef; ILExpression target, val; @@ -344,6 +344,31 @@ namespace ICSharpCode.Decompiler.ILAst } return false; } + + bool MatchRoslynStateAssignment(List block, int index, out int stateID) + { + // v = ldc.i4(stateId) + // stloc(cachedState, v) + // stfld(StateMachine::<>1__state, ldloc(this), v) + stateID = 0; + if (index < 0) + return false; + ILVariable v; + ILExpression val; + if (!block[index].Match(ILCode.Stloc, out v, out val) || !val.Match(ILCode.Ldc_I4, out stateID)) + return false; + ILExpression loadV; + if (!block[index + 1].MatchStloc(cachedStateVar, out loadV) || !loadV.MatchLdloc(v)) + return false; + ILExpression target; + FieldReference fieldRef; + if (block[index + 2].Match(ILCode.Stfld, out fieldRef, out target, out loadV)) { + return fieldRef.ResolveWithinSameModule() == stateField + && target.MatchThis() + && loadV.MatchLdloc(v); + } + return false; + } #endregion #region AnalyzeStateMachine @@ -450,18 +475,16 @@ namespace ICSharpCode.Decompiler.ILAst List ConvertFinally(List body) { List newBody = new List(body); + if (newBody.Count == 0) + return newBody; ILLabel endFinallyLabel; ILExpression ceqExpr; - if (newBody.Count > 0 && newBody[0].Match(ILCode.Brtrue, out endFinallyLabel, out ceqExpr)) { - ILExpression loadDoFinallyBodies, loadZero; - object unused; - if (ceqExpr.Match(ILCode.Ceq, out unused, out loadDoFinallyBodies, out loadZero)) { - int num; - if (loadDoFinallyBodies.MatchLdloc(doFinallyBodies) && loadZero.Match(ILCode.Ldc_I4, out num) && num == 0) { + if (newBody[0].Match(ILCode.Brtrue, out endFinallyLabel, out ceqExpr)) { + ILExpression condition; + if (MatchLogicNot(ceqExpr, out condition)) { + if (condition.MatchLdloc(doFinallyBodies)) { newBody.RemoveAt(0); - } - } else if (ceqExpr.Match(ILCode.LogicNot, out loadDoFinallyBodies)) { - if (loadDoFinallyBodies.MatchLdloc(doFinallyBodies)) { + } else if (condition.Code == ILCode.Clt && condition.Arguments[0].MatchLdloc(cachedStateVar) && condition.Arguments[1].MatchLdcI4(0)) { newBody.RemoveAt(0); } } @@ -469,6 +492,17 @@ namespace ICSharpCode.Decompiler.ILAst return newBody; } + bool MatchLogicNot(ILExpression expr, out ILExpression arg) + { + ILExpression loadZero; + object unused; + if (expr.Match(ILCode.Ceq, out unused, out arg, out loadZero)) { + int num; + return loadZero.Match(ILCode.Ldc_I4, out num) && num == 0; + } + return expr.Match(ILCode.LogicNot, out arg); + } + void HandleAwait(List newBody, out ILVariable awaiterVar, out FieldDefinition awaiterField, out int targetStateID) { // Handle the instructions prior to the exit out of the method to detect what is being awaited. @@ -509,9 +543,10 @@ namespace ICSharpCode.Decompiler.ILAst throw new SymbolicAnalysisFailedException(); // stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(0)) - if (!MatchStateAssignment(newBody.LastOrDefault(), out targetStateID)) - throw new SymbolicAnalysisFailedException(); - newBody.RemoveAt(newBody.Count - 1); // remove awaiter field assignment + if (MatchStateAssignment(newBody.LastOrDefault(), out targetStateID)) + newBody.RemoveAt(newBody.Count - 1); // remove awaiter field assignment + else if (MatchRoslynStateAssignment(newBody, newBody.Count - 3, out targetStateID)) + newBody.RemoveRange(newBody.Count - 3, 3); // remove awaiter field assignment } #endregion diff --git a/ICSharpCode.Decompiler/ILAst/PatternMatching.cs b/ICSharpCode.Decompiler/ILAst/PatternMatching.cs index 31fcf62b1..441088b90 100644 --- a/ICSharpCode.Decompiler/ILAst/PatternMatching.cs +++ b/ICSharpCode.Decompiler/ILAst/PatternMatching.cs @@ -167,5 +167,11 @@ namespace ICSharpCode.Decompiler.ILAst ILVariable v; return node.Match(ILCode.Stloc, out v, out expr) && v == expectedVar; } + + public static bool MatchLdcI4(this ILNode node, int expectedValue) + { + int v; + return node.Match(ILCode.Ldc_I4, out v) && v == expectedValue; + } } }