-
Notifications
You must be signed in to change notification settings - Fork 206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement a change in IL API to use RuntimeHelpers.Await<T>(Task<T>) and similar helpers. #2951
base: feature/async2-experiment
Are you sure you want to change the base?
Changes from 9 commits
42ec5c2
76ca9da
ed94235
6e1cd59
5c5566b
02de185
a1699c6
a67f3ea
21dc02b
4723c6a
066ad44
0a07d7b
03ddebc
ae17a3b
520da20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -178,8 +178,8 @@ public static unsafe ReadOnlySpan<T> CreateSpan<T>(RuntimeFieldHandle fldHandle) | |||
|
||||
#if !NATIVEAOT | ||||
[Intrinsic] | ||||
[MethodImpl(MethodImplOptions.NoInlining)] | ||||
[BypassReadyToRun] | ||||
[MethodImpl(MethodImplOptions.NoInlining | (MethodImplOptions)0x0400)] // NoInlining | Async | ||||
public static void AwaitAwaiterFromRuntimeAsync<TAwaiter>(TAwaiter awaiter) where TAwaiter : INotifyCompletion | ||||
{ | ||||
ref RuntimeAsyncAwaitState state = ref t_runtimeAsyncAwaitState; | ||||
|
@@ -193,10 +193,10 @@ public static void AwaitAwaiterFromRuntimeAsync<TAwaiter>(TAwaiter awaiter) wher | |||
} | ||||
|
||||
// Marked intrinsic since for JIT state machines this needs to be | ||||
// recognizes as an async2 call. | ||||
// recognized as an async2 call. | ||||
[Intrinsic] | ||||
[BypassReadyToRun] | ||||
[MethodImpl(MethodImplOptions.NoInlining)] | ||||
[MethodImpl(MethodImplOptions.NoInlining | (MethodImplOptions)0x0400)] // NoInlining | Async | ||||
public static void UnsafeAwaitAwaiterFromRuntimeAsync<TAwaiter>(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion | ||||
{ | ||||
ref RuntimeAsyncAwaitState state = ref t_runtimeAsyncAwaitState; | ||||
|
@@ -208,6 +208,73 @@ public static void UnsafeAwaitAwaiterFromRuntimeAsync<TAwaiter>(TAwaiter awaiter | |||
SuspendAsync2(sentinelContinuation); | ||||
return; | ||||
} | ||||
|
||||
// Marked intrinsic since this needs to be | ||||
// recognized as an async2 call. | ||||
[Intrinsic] | ||||
[BypassReadyToRun] | ||||
[MethodImpl(MethodImplOptions.NoInlining | (MethodImplOptions)0x0400)] // NoInlining | Async | ||||
public static T Await<T>(Task<T> task) | ||||
{ | ||||
TaskAwaiter<T> awaiter = task.GetAwaiter(); | ||||
if (!awaiter.IsCompleted) | ||||
{ | ||||
UnsafeAwaitAwaiterFromRuntimeAsync(awaiter); | ||||
} | ||||
|
||||
return awaiter.GetResult(); | ||||
} | ||||
|
||||
// Marked intrinsic since this needs to be | ||||
// recognized as an async2 call. | ||||
[Intrinsic] | ||||
[BypassReadyToRun] | ||||
[MethodImpl(MethodImplOptions.NoInlining | (MethodImplOptions)0x0400)] // NoInlining | Async | ||||
public static void Await(Task task) | ||||
{ | ||||
TaskAwaiter awaiter = task.GetAwaiter(); | ||||
if (!awaiter.IsCompleted) | ||||
{ | ||||
UnsafeAwaitAwaiterFromRuntimeAsync(awaiter); | ||||
} | ||||
|
||||
awaiter.GetResult(); | ||||
return; | ||||
} | ||||
|
||||
// Marked intrinsic since this needs to be | ||||
// recognized as an async2 call. | ||||
[Intrinsic] | ||||
[BypassReadyToRun] | ||||
[MethodImpl(MethodImplOptions.NoInlining | (MethodImplOptions)0x0400)] // NoInlining | Async | ||||
public static T Await<T>(ValueTask<T> task) | ||||
{ | ||||
ValueTaskAwaiter<T> awaiter = task.GetAwaiter(); | ||||
if (!awaiter.IsCompleted) | ||||
{ | ||||
UnsafeAwaitAwaiterFromRuntimeAsync(awaiter); | ||||
} | ||||
|
||||
return awaiter.GetResult(); | ||||
} | ||||
|
||||
// Marked intrinsic since this needs to be | ||||
// recognized as an async2 call. | ||||
[Intrinsic] | ||||
[BypassReadyToRun] | ||||
[MethodImpl(MethodImplOptions.NoInlining | (MethodImplOptions)0x0400)] // NoInlining | Async | ||||
public static void Await(ValueTask task) | ||||
{ | ||||
ValueTaskAwaiter awaiter = task.GetAwaiter(); | ||||
if (!awaiter.IsCompleted) | ||||
{ | ||||
UnsafeAwaitAwaiterFromRuntimeAsync(awaiter); | ||||
} | ||||
|
||||
awaiter.GetResult(); | ||||
return; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
} | ||||
|
||||
#endif | ||||
} | ||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,11 +34,19 @@ private static async2 Task Returns(C c) | |
AssertEqual(424242, c.Val.C); | ||
AssertEqual(42424242, c.Val.D); | ||
|
||
S<string> strings = await ReturnsStructGC(); | ||
AssertEqual("A", strings.A); | ||
AssertEqual("B", strings.B); | ||
AssertEqual("C", strings.C); | ||
AssertEqual("D", strings.D); | ||
// TODO: need to fix this | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jakobbotsch the change stresses calling via thunks and possibly introduced some scenarios that tests did not cover before. Remarkably, nearly everything works fine!! However, here I saw an assert and turned off one scenario. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've hit that before when encoding method/type spec tokens incorrectly. Can you verify that the tokens being encoded when we construct the IL for the variants look fine? |
||
|
||
// Throws around the following code when jitting continuation.Resume ( IL_STUB_AsyncResume ) | ||
// | ||
// // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup. | ||
// if (!pContextMD->IsSharedByGenericInstantiations()) | ||
// COMPlusThrow(kInvalidProgramException); | ||
// | ||
//S<string> strings = await ReturnsStructGC(); | ||
//AssertEqual("A", strings.A); | ||
//AssertEqual("B", strings.B); | ||
//AssertEqual("C", strings.C); | ||
//AssertEqual("D", strings.D); | ||
|
||
S<byte> bytes = await ReturnsBytes(); | ||
AssertEqual(4, bytes.A); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.