-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Closed
Closed
Copy link
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIruntime-async
Milestone
Description
We need a way to guarantee that unboxing/instantiating stubs do not introduce intermediate continuations. We used to consider this to just be an optimization, but this is a correctness problem for IValueTaskSource.
Example that shows the misbehavior:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
public class Program
{
public static void Main()
{
SynchronizationContext.SetSynchronizationContext(new MySyncContext());
new Program().TestAsync(new C()).GetAwaiter().GetResult();
}
private async Task TestAsync(IFace i)
{
await i.Foo<string>(0, 1, 2, 3, 4, 5, 6, 7, "value");
}
private struct C : IFace
{
public ValueTask Foo<T>(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, T value)
{
return new ValueTask(new Source(), 0);
}
private class Source : IValueTaskSource
{
public void GetResult(short token)
{
}
public ValueTaskSourceStatus GetStatus(short token)
{
return ValueTaskSourceStatus.Pending;
}
public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
{
Console.WriteLine("Saw " + flags);
Trace.Assert(flags == ValueTaskSourceOnCompletedFlags.UseSchedulingContext);
}
}
}
private interface IFace
{
ValueTask Foo<T>(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, T value);
}
private class MySyncContext : SynchronizationContext
{
}
}Output:
Async1: Saw UseSchedulingContext
Runtime async: Saw None
The continuation created by the instantiating stub gets in the way of getting to the right continuation context flags.
cc @VSadov
We need some mechanism to ensure the stubs just directly return the callee continuation on suspension, which is not tied into tailcalling.
It would almost be possible to use AsyncHelpers.AsyncCallContinuation() + AsyncHelpers.AsyncSuspend from the stubs, but the JIT will still do its own state machine expansion. Probably need some new "tail suspend" intrinsic.
Metadata
Metadata
Assignees
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIruntime-async