Browse Source

[async] Fix handling of doFinallyBodies.

async/await decompilation is now enabled by default and in the testcases.
pull/850/head
Daniel Grunwald 8 years ago
parent
commit
4bfdcdd8a2
  1. 2
      ICSharpCode.Decompiler/DecompilerSettings.cs
  2. 52
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

2
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -72,7 +72,7 @@ namespace ICSharpCode.Decompiler
} }
} }
bool asyncAwait = false; bool asyncAwait = true;
/// <summary> /// <summary>
/// Decompile async methods. /// Decompile async methods.

52
ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

@ -85,6 +85,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
AnalyzeStateMachine(function); AnalyzeStateMachine(function);
DetectAwaitPattern(function); DetectAwaitPattern(function);
CleanDoFinallyBodies(function);
context.Step("Translate fields to local accesses", function); context.Step("Translate fields to local accesses", function);
MarkGeneratedVariables(function); MarkGeneratedVariables(function);
@ -809,5 +810,56 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
} }
} }
/// <summary>
/// Eliminates usage of doFinallyBodies
/// </summary>
private void CleanDoFinallyBodies(ILFunction function)
{
if (doFinallyBodies == null) {
return; // roslyn-compiled code doesn't use doFinallyBodies
}
context.StepStartGroup("CleanDoFinallyBodies", function);
Block entryPoint = GetBodyEntryPoint(function.Body as BlockContainer);
if (entryPoint != null && entryPoint.Instructions[0].MatchStLoc(doFinallyBodies, out var value) && value.MatchLdcI4(1)) {
// Remove initial doFinallyBodies assignment, if it wasn't already removed when
// we rearranged the control flow.
entryPoint.Instructions.RemoveAt(0);
}
if (doFinallyBodies.StoreInstructions.Count != 0 || doFinallyBodies.AddressCount != 0) {
// misdetected another variable as doFinallyBodies?
// reintroduce the initial store of ldc.i4(1)
context.Step("Re-introduce misdetected doFinallyBodies", function);
((BlockContainer)function.Body).EntryPoint.Instructions.Insert(0,
new StLoc(doFinallyBodies, new LdcI4(1)));
return;
}
foreach (var tryFinally in function.Descendants.OfType<TryFinally>()) {
entryPoint = GetBodyEntryPoint(tryFinally.FinallyBlock as BlockContainer);
if (entryPoint?.Instructions[0] is IfInstruction ifInst) {
if (ifInst.Condition is LogicNot logicNot && logicNot.Argument.MatchLdLoc(doFinallyBodies)) {
context.Step("Remove if(doFinallyBodies) from try-finally", tryFinally);
// condition will always be false now that we're using 'await' instructions
entryPoint.Instructions.RemoveAt(0);
}
}
}
// if there's any remaining loads (there shouldn't be), replace them with the constant 1
foreach (LdLoc load in doFinallyBodies.LoadInstructions) {
load.ReplaceWith(new LdcI4(1) { ILRange = load.ILRange });
}
context.StepEndGroup(keepIfEmpty: true);
}
Block GetBodyEntryPoint(BlockContainer body)
{
if (body == null)
return null;
Block entryPoint = body.EntryPoint;
while (entryPoint.Instructions[0].MatchBranch(out var targetBlock) && targetBlock.IncomingEdgeCount == 1) {
entryPoint = targetBlock;
}
return entryPoint;
}
} }
} }

Loading…
Cancel
Save