Browse Source

[async] Fix await decompiler for pre-roslyn csc, at least in cases where the stack is empty during the await.

pull/850/head
Daniel Grunwald 8 years ago
parent
commit
6c7e2efa6c
  1. 2
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 28
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  3. 2
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  4. 10
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

2
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1760,7 +1760,7 @@ namespace ICSharpCode.Decompiler.CSharp
} }
return new UnaryOperatorExpression(UnaryOperatorType.Await, value.Expression) return new UnaryOperatorExpression(UnaryOperatorType.Await, value.Expression)
.WithILInstruction(inst) .WithILInstruction(inst)
.WithRR(new ResolveResult(inst?.GetResultMethod.ReturnType ?? SpecialType.UnknownType)); .WithRR(new ResolveResult(inst.GetResultMethod?.ReturnType ?? SpecialType.UnknownType));
} }
protected internal override TranslatedExpression VisitInvalidBranch(InvalidBranch inst, TranslationContext context) protected internal override TranslatedExpression VisitInvalidBranch(InvalidBranch inst, TranslationContext context)

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

@ -81,11 +81,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
InlineBodyOfMoveNext(function); InlineBodyOfMoveNext(function);
CleanUpBodyOfMoveNext(function);
// Copy-propagate temporaries holding a copy of 'this'.
foreach (var stloc in function.Descendants.OfType<StLoc>().Where(s => s.Variable.IsSingleDefinition && s.Value.MatchLdThis()).ToList()) {
CopyPropagation.Propagate(stloc, context);
}
AnalyzeStateMachine(function); AnalyzeStateMachine(function);
DetectAwaitPattern(function); DetectAwaitPattern(function);
@ -101,6 +97,26 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
function.RunTransforms(CSharpDecompiler.EarlyILTransforms(), context); function.RunTransforms(CSharpDecompiler.EarlyILTransforms(), context);
} }
private void CleanUpBodyOfMoveNext(ILFunction function)
{
context.StepStartGroup("CleanUpBodyOfMoveNext", function);
// Simplify stobj(ldloca) -> stloc
foreach (var stobj in function.Descendants.OfType<StObj>()) {
ExpressionTransforms.StObjToStLoc(stobj, context);
}
// Copy-propagate temporaries holding a copy of 'this'.
foreach (var stloc in function.Descendants.OfType<StLoc>().Where(s => s.Variable.IsSingleDefinition && s.Value.MatchLdThis()).ToList()) {
CopyPropagation.Propagate(stloc, context);
}
new RemoveDeadVariableInit().Run(function, context);
// Run inlining, but don't remove dead variables (they might get revived by TranslateFieldsToLocalAccess)
foreach (var block in function.Descendants.OfType<Block>()) {
ILInlining.InlineAllInBlock(block, context);
}
context.StepEndGroup();
}
#region MatchTaskCreationPattern #region MatchTaskCreationPattern
bool MatchTaskCreationPattern(ILFunction function) bool MatchTaskCreationPattern(ILFunction function)
{ {
@ -717,7 +733,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
pos++; pos++;
} }
if (block.Instructions[pos] is StLoc stlocCachedState) { if (block.Instructions[pos] is StLoc stlocCachedState) {
if (stlocCachedState.Variable.Kind == VariableKind.Local && stlocCachedState.Variable.Index == cachedStateVar.Index) { if (stlocCachedState.Variable.Kind == VariableKind.Local && stlocCachedState.Variable.Index == cachedStateVar?.Index) {
if (stlocCachedState.Value.MatchLdLoc(m1Var) || stlocCachedState.Value.MatchLdcI4(initialState)) if (stlocCachedState.Value.MatchLdLoc(m1Var) || stlocCachedState.Value.MatchLdcI4(initialState))
pos++; pos++;
} }

2
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -237,7 +237,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
&& TypeUtils.IsCompatibleTypeForMemoryAccess(new ByReferenceType(v.Type), inst.Type) && TypeUtils.IsCompatibleTypeForMemoryAccess(new ByReferenceType(v.Type), inst.Type)
&& inst.UnalignedPrefix == 0 && inst.UnalignedPrefix == 0
&& !inst.IsVolatile) { && !inst.IsVolatile) {
context.Step("stobj(ldloca(v), ...) => stloc(v, ...)", inst); context.Step($"stobj(ldloca {v.Name}, ...) => stloc {v.Name}(...)", inst);
inst.ReplaceWith(new StLoc(v, inst.Value)); inst.ReplaceWith(new StLoc(v, inst.Value));
return true; return true;
} }

10
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -28,24 +28,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary> /// </summary>
public class ILInlining : IILTransform, IBlockTransform public class ILInlining : IILTransform, IBlockTransform
{ {
ILTransformContext context;
public void Run(ILFunction function, ILTransformContext context) public void Run(ILFunction function, ILTransformContext context)
{ {
this.context = context;
foreach (var block in function.Descendants.OfType<Block>()) { foreach (var block in function.Descendants.OfType<Block>()) {
InlineAllInBlock(block); InlineAllInBlock(block, context);
} }
function.Variables.RemoveDead(); function.Variables.RemoveDead();
} }
public void Run(Block block, BlockTransformContext context) public void Run(Block block, BlockTransformContext context)
{ {
this.context = context; InlineAllInBlock(block, context);
InlineAllInBlock(block);
} }
public bool InlineAllInBlock(Block block) public static bool InlineAllInBlock(Block block, ILTransformContext context)
{ {
bool modified = false; bool modified = false;
int i = 0; int i = 0;

Loading…
Cancel
Save