Skip to content
Permalink
Browse files

Fix #1782: AsyncAwaitDecompiler for methods in struct

  • Loading branch information...
dgrunwald committed Nov 5, 2019
1 parent fc95f30 commit eaecedd8ea4c6c0b6c15e468fafea59ab746c2d9
@@ -199,6 +199,19 @@ async Task<int> Nested(int i)
#endif
}

public struct AsyncInStruct
{
private int i;

public async Task<int> Test(AsyncInStruct xx)
{
xx.i++;
i++;
await Task.Yield();
return i + xx.i;
}
}

public struct HopToThreadPoolAwaitable : INotifyCompletion
{
public bool IsCompleted {
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
@@ -33,5 +34,32 @@ public static async IAsyncEnumerable<int> InfiniteLoopWithAwait()
}
yield break;
}

public async IAsyncEnumerable<int> AwaitInFinally()
{
try {
Console.WriteLine("try");
yield return 1;
Console.WriteLine("end try");
} finally {
Console.WriteLine("finally");
await Task.Yield();
Console.WriteLine("end finally");
}
}
}

public struct TestStruct
{
private int i;

public async IAsyncEnumerable<int> AwaitInStruct(TestStruct xx)
{
xx.i++;
i++;
await Task.Yield();
yield return i;
yield return xx.i;
}
}
}
@@ -326,11 +326,15 @@ leave IL_0000 (or ret for non-void async methods)
// stfld StateMachine.field(ldloca stateMachine, ldvar(param))
if (!MatchStFld(body[pos], stateMachineVar, out var field, out var fieldInit))
return false;
if (!fieldInit.MatchLdLoc(out var v))
return false;
if (v.Kind != VariableKind.Parameter)
if (fieldInit.MatchLdLoc(out var v) && v.Kind == VariableKind.Parameter) {
// OK, copies parameter into state machine
fieldToParameterMap[field] = v;
} else if (fieldInit is LdObj ldobj && ldobj.Target.MatchLdThis()) {
// stfld <>4__this(ldloc stateMachine, ldobj AsyncInStruct(ldloc this))
fieldToParameterMap[field] = ((LdLoc)ldobj.Target).Variable;
} else {
return false;
fieldToParameterMap[field] = v;
}
}

return true;
@@ -413,9 +417,13 @@ private bool MatchAsyncEnumeratorCreationPattern(ILFunction function)
pos++;

while (MatchStFld(body.Instructions[pos], v, out var field, out var value)) {
if (!value.MatchLdLoc(out var p))
if (value.MatchLdLoc(out var p) && p.Kind == VariableKind.Parameter) {
fieldToParameterMap[field] = p;
} else if (value is LdObj ldobj && ldobj.Target.MatchLdThis()) {
fieldToParameterMap[field] = ((LdLoc)ldobj.Target).Variable;
} else {
return false;
fieldToParameterMap[field] = p;
}
pos++;
}
if (!body.Instructions[pos].MatchReturn(out var returnValue))
@@ -967,18 +975,27 @@ ILInstruction FindYieldBreakTarget(Block block)

private bool SimplifyIfDisposeMode(Block block)
{
// Occasionally Roslyn optimizes out an "if (disposeMode)", but keeps the
// disposeMode field access. Get rid of those field accesses:
block.Instructions.RemoveAll(MatchLdDisposeMode);

// if (logic.not(ldfld disposeMode(ldloc this))) br falseInst
// br trueInst
if (!block.MatchIfAtEndOfBlock(out var condition, out _, out var falseInst))
return false;
if (!condition.MatchLdFld(out var target, out var field))
return false;
if (!(target.MatchLdThis() && field.MemberDefinition == disposeModeField))
if (!MatchLdDisposeMode(condition))
return false;
context.Step($"SimplifyIfDisposeMode({block.StartILOffset:x4})", block);
block.Instructions[block.Instructions.Count - 2] = falseInst;
block.Instructions.RemoveAt(block.Instructions.Count - 1);
return true;

bool MatchLdDisposeMode(ILInstruction inst)
{
if (!inst.MatchLdFld(out var target, out var field))
return false;
return target.MatchLdThis() && field.MemberDefinition == disposeModeField;
}
}

bool AnalyzeAwaitBlock(Block block, out ILVariable awaiter, out IField awaiterField, out int state, out int yieldOffset)

0 comments on commit eaecedd

Please sign in to comment.
You can’t perform that action at this time.