Browse Source

Add tests for 'async IAsyncEnumerable'.

Remove [AsyncIteratorStateMachine] attribute and left-over ldc.i4 instructions.
pull/1730/head
Daniel Grunwald 6 years ago
parent
commit
de33e79384
  1. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  3. 37
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs
  4. 6
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  5. 7
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  6. 6
      ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs
  7. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs

1
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -81,6 +81,7 @@
<Compile Include="DisassemblerPrettyTestRunner.cs" /> <Compile Include="DisassemblerPrettyTestRunner.cs" />
<Compile Include="TestCases\Correctness\StringConcat.cs" /> <Compile Include="TestCases\Correctness\StringConcat.cs" />
<Compile Include="TestCases\ILPretty\ConstantBlobs.cs" /> <Compile Include="TestCases\ILPretty\ConstantBlobs.cs" />
<None Include="TestCases\Pretty\AsyncStreams.cs" />
<None Include="TestCases\Pretty\AsyncUsing.cs" /> <None Include="TestCases\Pretty\AsyncUsing.cs" />
<Compile Include="TestCases\Pretty\OutVariables.cs" /> <Compile Include="TestCases\Pretty\OutVariables.cs" />
<Compile Include="TestCases\Pretty\CustomTaskType.cs" /> <Compile Include="TestCases\Pretty\CustomTaskType.cs" />

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -307,6 +307,12 @@ namespace ICSharpCode.Decompiler.Tests
Run(cscOptions: cscOptions); Run(cscOptions: cscOptions);
} }
[Test]
public void AsyncStreams([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}
[Test] [Test]
public void AsyncUsing([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions) public void AsyncUsing([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions)
{ {

37
ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs

@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class AsyncStreams
{
public static async IAsyncEnumerable<int> CountTo(int until)
{
for (int i = 0; i < until; i++) {
yield return i;
await Task.Delay(10);
}
}
public static async IAsyncEnumerable<int> AlwaysThrow()
{
throw null;
yield break;
}
public static async IAsyncEnumerator<int> InfiniteLoop()
{
while (true) {
}
yield break;
}
public static async IAsyncEnumerable<int> InfiniteLoopWithAwait()
{
while (true) {
await Task.Delay(10);
}
yield break;
}
}
}

6
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -1343,7 +1343,11 @@ namespace ICSharpCode.Decompiler.CSharp
if (localSettings.DecompileMemberBodies && !body.Descendants.Any(d => d is YieldReturnStatement || d is YieldBreakStatement)) { if (localSettings.DecompileMemberBodies && !body.Descendants.Any(d => d is YieldReturnStatement || d is YieldBreakStatement)) {
body.Add(new YieldBreakStatement()); body.Add(new YieldBreakStatement());
} }
RemoveAttribute(entityDecl, KnownAttribute.IteratorStateMachine); if (function.IsAsync) {
RemoveAttribute(entityDecl, KnownAttribute.AsyncIteratorStateMachine);
} else {
RemoveAttribute(entityDecl, KnownAttribute.IteratorStateMachine);
}
if (function.StateMachineCompiledWithMono) { if (function.StateMachineCompiledWithMono) {
RemoveAttribute(entityDecl, KnownAttribute.DebuggerHidden); RemoveAttribute(entityDecl, KnownAttribute.DebuggerHidden);
} }

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

@ -174,9 +174,14 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
CopyPropagation.Propagate(stloc, context); CopyPropagation.Propagate(stloc, context);
} }
new RemoveDeadVariableInit().Run(function, 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>()) { foreach (var block in function.Descendants.OfType<Block>()) {
// Run inlining, but don't remove dead variables (they might get revived by TranslateFieldsToLocalAccess)
ILInlining.InlineAllInBlock(function, block, context); ILInlining.InlineAllInBlock(function, block, context);
if (IsAsyncEnumerator) {
// Remove lone 'ldc.i4', those are sometimes left over after C# compiler
// optimizes out stores to the state variable.
block.Instructions.RemoveAll(inst => inst.OpCode == OpCode.LdcI4);
}
} }
context.StepEndGroup(); context.StepEndGroup();
} }

6
ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs

@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
RemoveNopInstructions(block); RemoveNopInstructions(block);
RemoveDeadStackStores(block, aggressive: context.Settings.RemoveDeadStores); RemoveDeadStackStores(block, context);
InlineVariableInReturnBlock(block, context); InlineVariableInReturnBlock(block, context);
// 1st pass SimplifySwitchInstruction before SimplifyBranchChains() // 1st pass SimplifySwitchInstruction before SimplifyBranchChains()
@ -70,13 +70,15 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
block.Instructions.RemoveAll(inst => inst.OpCode == OpCode.Nop); block.Instructions.RemoveAll(inst => inst.OpCode == OpCode.Nop);
} }
private void RemoveDeadStackStores(Block block, bool aggressive) private static void RemoveDeadStackStores(Block block, ILTransformContext context)
{ {
bool aggressive = context.Settings.RemoveDeadStores;
// Previously copy propagation did this; // Previously copy propagation did this;
// ideally the ILReader would already do this, // ideally the ILReader would already do this,
// for now do this here (even though it's not control-flow related). // for now do this here (even though it's not control-flow related).
for (int i = block.Instructions.Count - 1; i >= 0; i--) { for (int i = block.Instructions.Count - 1; i >= 0; i--) {
if (block.Instructions[i] is StLoc stloc && stloc.Variable.IsSingleDefinition && stloc.Variable.LoadCount == 0 && stloc.Variable.Kind == VariableKind.StackSlot) { if (block.Instructions[i] is StLoc stloc && stloc.Variable.IsSingleDefinition && stloc.Variable.LoadCount == 0 && stloc.Variable.Kind == VariableKind.StackSlot) {
context.Step($"Remove dead stack store {stloc.Variable.Name}", stloc);
if (aggressive ? SemanticHelper.IsPure(stloc.Value.Flags) : IsSimple(stloc.Value)) { if (aggressive ? SemanticHelper.IsPure(stloc.Value.Flags) : IsSimple(stloc.Value)) {
Debug.Assert(SemanticHelper.IsPure(stloc.Value.Flags)); Debug.Assert(SemanticHelper.IsPure(stloc.Value.Flags));
block.Instructions.RemoveAt(i++); block.Instructions.RemoveAt(i++);

2
ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs

@ -64,6 +64,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
IteratorStateMachine, IteratorStateMachine,
AsyncStateMachine, AsyncStateMachine,
AsyncMethodBuilder, AsyncMethodBuilder,
AsyncIteratorStateMachine,
// Field attributes: // Field attributes:
FieldOffset, FieldOffset,
@ -131,6 +132,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(IteratorStateMachineAttribute)), new TopLevelTypeName("System.Runtime.CompilerServices", nameof(IteratorStateMachineAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(AsyncStateMachineAttribute)), new TopLevelTypeName("System.Runtime.CompilerServices", nameof(AsyncStateMachineAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", "AsyncMethodBuilderAttribute"), new TopLevelTypeName("System.Runtime.CompilerServices", "AsyncMethodBuilderAttribute"),
new TopLevelTypeName("System.Runtime.CompilerServices", "AsyncIteratorStateMachineAttribute"),
// Field attributes: // Field attributes:
new TopLevelTypeName("System.Runtime.InteropServices", nameof(FieldOffsetAttribute)), new TopLevelTypeName("System.Runtime.InteropServices", nameof(FieldOffsetAttribute)),
new TopLevelTypeName("System", nameof(NonSerializedAttribute)), new TopLevelTypeName("System", nameof(NonSerializedAttribute)),

Loading…
Cancel
Save