From b34e3645d52903a7f0c8d3bfaae95673b34a57b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Loba=C4=8Devski?= Date: Mon, 20 Jul 2020 14:54:13 +0300 Subject: [PATCH] Fix async/await decompilation for Roslyn 3.6 Closes https://github.com/0xd4d/dnSpy/issues/1488 --- .../ILAst/MicrosoftAsyncDecompiler.cs | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/ICSharpCode.Decompiler/ILAst/MicrosoftAsyncDecompiler.cs b/ICSharpCode.Decompiler/ILAst/MicrosoftAsyncDecompiler.cs index 703ae2158c..a7365de5e3 100644 --- a/ICSharpCode.Decompiler/ILAst/MicrosoftAsyncDecompiler.cs +++ b/ICSharpCode.Decompiler/ILAst/MicrosoftAsyncDecompiler.cs @@ -68,26 +68,42 @@ bool MatchTaskCreationPattern(ILBlock method) { // C# + int pos = body.Count - 2; ILVariable stateMachineVar, builderVar; - if (!MatchStartCall(body[body.Count - 2], out stateMachineVar, out builderVar) || builderVar == null) - return false; - if (!MatchBuilderField(body[body.Count - 3], stateMachineVar, builderVar)) + if (MatchStartCall(body[pos], out stateMachineVar, out builderVar) && builderVar != null) { + ILExpression loadBuilderExpr; + if (!body[pos - 1].MatchStloc(builderVar, out loadBuilderExpr)) + return false; + if (!MatchBuilderField(stateMachineVar, loadBuilderExpr)) + return false; + } + else if (MatchStartCall(body[pos], out stateMachineVar)) { + IMethod startMethod; + ILExpression loadStartTarget, loadStartArgument; + if (!body[pos++].Match(ILCode.Call, out startMethod, out loadStartTarget, out loadStartArgument)) + return false; + if (!MatchBuilderField(stateMachineVar, loadStartTarget)) + return false; + } + else return false; + + if (!MatchReturnTask(body[body.Count - 1], stateMachineVar)) return false; // Check the last field assignment - this should be the state field ILExpression initialStateExpr; - if (!MatchStFld(body[body.Count - 4], stateMachineVar, stateMachineTypeIsValueType, out stateField, out initialStateExpr)) + if (!MatchStFld(body[pos - 2], stateMachineVar, stateMachineTypeIsValueType, out stateField, out initialStateExpr)) return false; if (!initialStateExpr.Match(ILCode.Ldc_I4, out initialState)) return false; if (initialState != -1) return false; - if (!MatchCallCreate(body[body.Count - 5], stateMachineVar)) + if (!MatchCallCreate(body[pos - 3], stateMachineVar)) return false; - if (!InitializeFieldToParameterMap(body, body.Count - 5, stateMachineVar)) + if (!InitializeFieldToParameterMap(body, pos - 3, stateMachineVar)) return false; return true; @@ -135,14 +151,18 @@ bool IsPerhapsVisualBasicKickoffMethod(ILExpression expr, out ILVariable stateMa } static readonly UTF8String nameCtor = new UTF8String(".ctor"); - bool MatchBuilderField(ILNode expr, ILVariable stateMachineVar, ILVariable builderVar) { - ILExpression loadBuilderExpr; - if (!expr.MatchStloc(builderVar, out loadBuilderExpr)) - return false; + bool MatchBuilderField(ILVariable stateMachineVar, ILExpression loadBuilderExpr) { IField builderFieldRef; ILExpression loadStateMachineForBuilderExpr; - if (!loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr)) + if (loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr)) { + // OK, calling Start on copy of stateMachine.<>t__builder + } + else if (loadBuilderExpr.Match(ILCode.Ldflda, out builderFieldRef, out loadStateMachineForBuilderExpr)) { + // OK, Roslyn 3.6 started directly calling Start without making a copy + } + else { return false; + } if (!(loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar) || loadStateMachineForBuilderExpr.MatchLdloc(stateMachineVar))) return false; builderField = builderFieldRef.ResolveFieldWithinSameModule();