diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs index 81d9f982c4e7ea..0eeea7e127dfd0 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs @@ -15,6 +15,42 @@ namespace System.Runtime.CompilerServices { + internal struct ExecutionAndSyncBlockStore + { + // Store current ExecutionContext and SynchronizationContext as "previousXxx". + // This allows us to restore them and undo any Context changes made in stateMachine.MoveNext + // so that they won't "leak" out of the first await. + public ExecutionContext? _previousExecutionCtx; + public SynchronizationContext? _previousSyncCtx; + public Thread _thread; + + public void Push() + { + _thread = Thread.CurrentThread; + // Here we get the execution context for synchronous restoring, + // not for flowing across suspension to potentially another thread. + // Therefore we do not need to worry about IsFlowSuppressed + _previousExecutionCtx = _thread._executionContext; + _previousSyncCtx = _thread._synchronizationContext; + } + + public void Pop() + { + // The common case is that these have not changed, so avoid the cost of a write barrier if not needed. + if (_previousSyncCtx != _thread._synchronizationContext) + { + // Restore changed SynchronizationContext back to previous + _thread._synchronizationContext = _previousSyncCtx; + } + + ExecutionContext? currentExecutionCtx = _thread._executionContext; + if (_previousExecutionCtx != currentExecutionCtx) + { + ExecutionContext.RestoreChangedContextToThread(_thread, _previousExecutionCtx, currentExecutionCtx); + } + } + } + [Flags] // Keep in sync with CORINFO_CONTINUATION_FLAGS internal enum ContinuationFlags @@ -170,13 +206,12 @@ public static partial class AsyncHelpers [Intrinsic] private static void TailAwait() => throw new UnreachableException(); - // This is state used by suspension/resumption machinery and stored in - // the two places that initiate runtime async chains: either a - // task-returning thunk, or DispatchContinuations. A pointer to this - // state is kept in the runtime async TLS. This storage method avoids - // costly write barriers on the hot path of suspension/resumption. - private ref struct RuntimeAsyncStackState + // Used during suspensions to hold the continuation chain and on what we are waiting. + // Methods like FinalizeTaskReturningThunk will unlink the state and wrap into a Task. + private struct RuntimeAsyncAwaitState { + public Continuation? SentinelContinuation; + // The following are the possible introducers of asynchrony into a chain of awaits. // In other words - when we build a chain of continuations it would be logicaly attached // to one of these notifiers. @@ -185,82 +220,17 @@ private ref struct RuntimeAsyncStackState public ValueTaskSourceNotifier? ValueTaskSourceNotifier; public Task? TaskNotifier; - // When we suspend in the leaf, the contexts are captured into these fields. - public ExecutionContext? LeafExecutionContext; - public SynchronizationContext? LeafSynchronizationContext; - - // When we enter the root of the async chain (either an async thunk - // or DispatchContinuations), the contexts are captured into these - // fields. - public ExecutionContext? RootExecutionContext; - public SynchronizationContext? RootSynchronizationContext; - - public unsafe RuntimeAsyncStackState* Next; - - public void Push(Thread thread) - { - RootExecutionContext = thread._executionContext; - RootSynchronizationContext = thread._synchronizationContext; - } - - public void Pop(Thread thread) - { - // The common case is that these have not changed, so avoid the cost of a write barrier if not needed. - if (RootSynchronizationContext != thread._synchronizationContext) - { - // Restore changed SynchronizationContext back to previous - thread._synchronizationContext = RootSynchronizationContext; - } - - ExecutionContext? currentExecutionCtx = thread._executionContext; - if (RootExecutionContext != currentExecutionCtx) - { - ExecutionContext.RestoreChangedContextToThread(thread, RootExecutionContext, currentExecutionCtx); - } - } - } - - // Used during suspensions to hold the continuation chain and on what we are waiting. - // Methods like FinalizeTaskReturningThunk will unlink the state and wrap into a Task. - private unsafe struct RuntimeAsyncAwaitState - { - public Continuation? SentinelContinuation; - - // We cache the thread here to avoid unnecessary repeated TLS lookups. - public Thread CurrentThread; - - public RuntimeAsyncStackState* StackState; + public ExecutionContext? ExecutionContext; + public SynchronizationContext? SynchronizationContext; public void CaptureContexts() { - // CaptureContext is called from leaf await helpers. We either just started a runtime async chain - // (from a thunk), or we came from DispatchContinuations (on resumption). - // Both cases have already initialized CurrentThread. - Thread curThread = CurrentThread; - Debug.Assert(curThread != null); - Debug.Assert(StackState != null); + Thread curThread = Thread.CurrentThreadAssumedInitialized; // Here we get the execution context for presenting to the notifier, // not for flowing across suspension to potentially another thread. // Therefore we do not need to worry about IsFlowSuppressed - StackState->LeafExecutionContext = curThread._executionContext; - StackState->LeafSynchronizationContext = curThread._synchronizationContext; - } - - // At the start of an async chain (task-returning thunk or DispatchContinuations) this function - // is called - public void Push(RuntimeAsyncStackState* stackState) - { - stackState->Next = StackState; - StackState = stackState; - stackState->Push(CurrentThread ??= Thread.CurrentThread); - } - - // This function is called at the end of an async chain - public void Pop() - { - Debug.Assert(CurrentThread != null); - StackState->Pop(CurrentThread); - StackState = StackState->Next; + ExecutionContext = curThread._executionContext; + SynchronizationContext = curThread._synchronizationContext; } } @@ -327,18 +297,20 @@ private static unsafe Continuation AllocContinuationClass(Continuation prevConti /// Task or a ValueTaskNotifier whose completion we are awaiting. [BypassReadyToRun] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.Async)] - private static unsafe void TransparentAwait(object o) + private static void TransparentAwait(object o) { ref RuntimeAsyncAwaitState state = ref t_runtimeAsyncAwaitState; - Continuation? sentinelContinuation = state.SentinelContinuation ??= new Continuation(); + Continuation? sentinelContinuation = state.SentinelContinuation; + if (sentinelContinuation == null) + state.SentinelContinuation = sentinelContinuation = new Continuation(); if (o is Task t) { - state.StackState->TaskNotifier = t; + state.TaskNotifier = t; } else { - state.StackState->ValueTaskSourceNotifier = (ValueTaskSourceNotifier)o; + state.ValueTaskSourceNotifier = (ValueTaskSourceNotifier)o; } state.CaptureContexts(); @@ -371,19 +343,13 @@ void ITaskCompletionAction.Invoke(Task completingTask) bool ITaskCompletionAction.InvokeMayRunArbitraryCode => true; - private Action GetContinuationAction() - { - object? action = m_action; - Debug.Assert(action is Action); - return Unsafe.As(action); - } + private Action GetContinuationAction() => (Action)m_action!; private Continuation MoveContinuationState() { - object? stateObject = m_stateObject; - Debug.Assert(stateObject is Continuation); + Continuation continuation = (Continuation)m_stateObject!; m_stateObject = null; - return Unsafe.As(stateObject); + return continuation; } private void SetContinuationState(Continuation value) @@ -392,23 +358,23 @@ private void SetContinuationState(Continuation value) m_stateObject = value; } - internal unsafe bool HandleSuspended(ref RuntimeAsyncAwaitState state) + internal bool HandleSuspended() { - Thread currentThread = state.CurrentThread; - Debug.Assert(currentThread != null); + ref RuntimeAsyncAwaitState state = ref t_runtimeAsyncAwaitState; - RuntimeAsyncStackState* stackState = state.StackState; - ExecutionContext? suspendingExecutionContext = stackState->LeafExecutionContext; - SynchronizationContext? suspendingSyncContext = stackState->LeafSynchronizationContext; - if (suspendingExecutionContext != currentThread._executionContext) - { - currentThread._executionContext = suspendingExecutionContext; - } + RestoreContextsOnSuspension(false, state.ExecutionContext, state.SynchronizationContext); - if (suspendingSyncContext != currentThread._synchronizationContext) - { - currentThread._synchronizationContext = suspendingSyncContext; - } + ICriticalNotifyCompletion? critNotifier = state.CriticalNotifier; + INotifyCompletion? notifier = state.Notifier; + ValueTaskSourceNotifier? vtsNotifier = state.ValueTaskSourceNotifier; + Task? taskNotifier = state.TaskNotifier; + + state.CriticalNotifier = null; + state.Notifier = null; + state.ValueTaskSourceNotifier = null; + state.TaskNotifier = null; + state.ExecutionContext = null; + state.SynchronizationContext = null; Continuation sentinelContinuation = state.SentinelContinuation!; Continuation headContinuation = sentinelContinuation.Next!; @@ -427,11 +393,11 @@ internal unsafe bool HandleSuspended(ref RuntimeAsyncAwaitState state) try { - if (stackState->CriticalNotifier is { } critNotifier) + if (critNotifier != null) { critNotifier.UnsafeOnCompleted(GetContinuationAction()); } - else if (stackState->TaskNotifier is { } taskNotifier) + else if (taskNotifier != null) { // Runtime async callable wrapper for task returning // method. This implements the context transparent @@ -441,7 +407,7 @@ internal unsafe bool HandleSuspended(ref RuntimeAsyncAwaitState state) ThreadPool.UnsafeQueueUserWorkItemInternal(this, preferLocal: true); } } - else if (stackState->ValueTaskSourceNotifier is { } valueTaskSourceNotifier) + else if (vtsNotifier != null) { // The awaiter must inform the ValueTaskSource on whether the continuation // wants to run on a context, although the source may decide to ignore the suggestion. @@ -476,12 +442,12 @@ internal unsafe bool HandleSuspended(ref RuntimeAsyncAwaitState state) // Clear continuation flags, so that continuation runs transparently nextUserContinuation.Flags &= ~continueFlags; - valueTaskSourceNotifier.OnCompleted(s_runContinuationAction, this, configFlags); + vtsNotifier.OnCompleted(s_runContinuationAction, this, configFlags); } else { - Debug.Assert(stackState->Notifier != null); - stackState->Notifier!.OnCompleted(GetContinuationAction()); + Debug.Assert(notifier != null); + notifier.OnCompleted(GetContinuationAction()); } return true; @@ -494,7 +460,7 @@ internal unsafe bool HandleSuspended(ref RuntimeAsyncAwaitState state) return false; } - internal void InstrumentedHandleSuspended(AsyncInstrumentation.Flags flags, ref RuntimeAsyncAwaitState state, Continuation? newContinuation = null) + internal void InstrumentedHandleSuspended(AsyncInstrumentation.Flags flags, Continuation? newContinuation = null) { if (AsyncInstrumentation.IsEnabled.AsyncDebugger(flags)) { @@ -502,7 +468,7 @@ internal void InstrumentedHandleSuspended(AsyncInstrumentation.Flags flags, ref AsyncDebugger.HandleSuspended(nextContinuation, newContinuation); - if (!HandleSuspended(ref state)) + if (!HandleSuspended()) { AsyncDebugger.HandleSuspendedFailed(this, nextContinuation); } @@ -510,7 +476,7 @@ internal void InstrumentedHandleSuspended(AsyncInstrumentation.Flags flags, ref return; } - HandleSuspended(ref state); + HandleSuspended(); } #pragma warning disable CA1822 // Mark members as static @@ -534,17 +500,13 @@ private unsafe void DispatchContinuations() } } - RuntimeAsyncStackState stackState = default; - - ref RuntimeAsyncAwaitState awaitState = ref t_runtimeAsyncAwaitState; - awaitState.Push(&stackState); - - ref AsyncDispatcherInfo* refDispatcherInfo = ref AsyncDispatcherInfo.t_current; + ExecutionAndSyncBlockStore contexts = default; + contexts.Push(); AsyncDispatcherInfo asyncDispatcherInfo; - asyncDispatcherInfo.Next = refDispatcherInfo; + asyncDispatcherInfo.Next = AsyncDispatcherInfo.t_current; asyncDispatcherInfo.NextContinuation = MoveContinuationState(); - refDispatcherInfo = &asyncDispatcherInfo; + AsyncDispatcherInfo.t_current = &asyncDispatcherInfo; while (true) { @@ -562,10 +524,10 @@ private unsafe void DispatchContinuations() if (newContinuation != null) { newContinuation.Next = nextContinuation; - HandleSuspended(ref awaitState); + HandleSuspended(); - awaitState.Pop(); - refDispatcherInfo = asyncDispatcherInfo.Next; + contexts.Pop(); + AsyncDispatcherInfo.t_current = asyncDispatcherInfo.Next; return; } } @@ -580,8 +542,9 @@ private unsafe void DispatchContinuations() TrySetCanceled(oce.CancellationToken, oce) : TrySetException(ex); - awaitState.Pop(); - refDispatcherInfo = asyncDispatcherInfo.Next; + contexts.Pop(); + + AsyncDispatcherInfo.t_current = asyncDispatcherInfo.Next; if (!successfullySet) { @@ -599,8 +562,9 @@ private unsafe void DispatchContinuations() { bool successfullySet = TrySetResult(m_result); - awaitState.Pop(); - refDispatcherInfo = asyncDispatcherInfo.Next; + contexts.Pop(); + + AsyncDispatcherInfo.t_current = asyncDispatcherInfo.Next; if (!successfullySet) { @@ -612,8 +576,8 @@ private unsafe void DispatchContinuations() if (QueueContinuationFollowUpActionIfNecessary(asyncDispatcherInfo.NextContinuation)) { - awaitState.Pop(); - refDispatcherInfo = asyncDispatcherInfo.Next; + contexts.Pop(); + AsyncDispatcherInfo.t_current = asyncDispatcherInfo.Next; return; } @@ -621,8 +585,8 @@ private unsafe void DispatchContinuations() { SetContinuationState(asyncDispatcherInfo.NextContinuation); - awaitState.Pop(); - refDispatcherInfo = asyncDispatcherInfo.Next; + contexts.Pop(); + AsyncDispatcherInfo.t_current = asyncDispatcherInfo.Next; InstrumentedDispatchContinuations(AsyncInstrumentation.ActiveFlags); return; @@ -633,17 +597,13 @@ private unsafe void DispatchContinuations() [StackTraceHidden] private unsafe void InstrumentedDispatchContinuations(AsyncInstrumentation.Flags flags) { - RuntimeAsyncStackState stackState = default; - - ref RuntimeAsyncAwaitState awaitState = ref t_runtimeAsyncAwaitState; - awaitState.Push(&stackState); - - ref AsyncDispatcherInfo* refDispatcherInfo = ref AsyncDispatcherInfo.t_current; + ExecutionAndSyncBlockStore contexts = default; + contexts.Push(); AsyncDispatcherInfo asyncDispatcherInfo; - asyncDispatcherInfo.Next = refDispatcherInfo; + asyncDispatcherInfo.Next = AsyncDispatcherInfo.t_current; asyncDispatcherInfo.NextContinuation = MoveContinuationState(); - refDispatcherInfo = &asyncDispatcherInfo; + AsyncDispatcherInfo.t_current = &asyncDispatcherInfo; RuntimeAsyncInstrumentationHelpers.ResumeRuntimeAsyncContext(this, ref asyncDispatcherInfo, flags); @@ -665,10 +625,10 @@ private unsafe void InstrumentedDispatchContinuations(AsyncInstrumentation.Flags { newContinuation.Next = nextContinuation; RuntimeAsyncInstrumentationHelpers.SuspendRuntimeAsyncContext(flags, curContinuation, newContinuation); - InstrumentedHandleSuspended(flags, ref awaitState, newContinuation); + InstrumentedHandleSuspended(flags, newContinuation); - awaitState.Pop(); - refDispatcherInfo = asyncDispatcherInfo.Next; + contexts.Pop(); + AsyncDispatcherInfo.t_current = asyncDispatcherInfo.Next; return; } @@ -687,8 +647,9 @@ private unsafe void InstrumentedDispatchContinuations(AsyncInstrumentation.Flags TrySetCanceled(oce.CancellationToken, oce) : TrySetException(ex); - awaitState.Pop(); - refDispatcherInfo = asyncDispatcherInfo.Next; + contexts.Pop(); + + AsyncDispatcherInfo.t_current = asyncDispatcherInfo.Next; if (!successfullySet) { @@ -710,8 +671,9 @@ private unsafe void InstrumentedDispatchContinuations(AsyncInstrumentation.Flags bool successfullySet = TrySetResult(m_result); - awaitState.Pop(); - refDispatcherInfo = asyncDispatcherInfo.Next; + contexts.Pop(); + + AsyncDispatcherInfo.t_current = asyncDispatcherInfo.Next; if (!successfullySet) { @@ -725,8 +687,8 @@ private unsafe void InstrumentedDispatchContinuations(AsyncInstrumentation.Flags { RuntimeAsyncInstrumentationHelpers.SuspendRuntimeAsyncContext(ref asyncDispatcherInfo, flags, curContinuation); - awaitState.Pop(); - refDispatcherInfo = asyncDispatcherInfo.Next; + contexts.Pop(); + AsyncDispatcherInfo.t_current = asyncDispatcherInfo.Next; return; } @@ -833,7 +795,7 @@ private bool QueueContinuationFollowUpActionIfNecessary(Continuation continuatio }; } - private static void InstrumentedFinalizeRuntimeAsyncTask(RuntimeAsyncTask task, ref RuntimeAsyncAwaitState state, AsyncInstrumentation.Flags flags) + private static void InstrumentedFinalizeRuntimeAsyncTask(RuntimeAsyncTask task, AsyncInstrumentation.Flags flags) { if (AsyncInstrumentation.IsEnabled.CreateAsyncContext(flags)) { @@ -844,54 +806,54 @@ private static void InstrumentedFinalizeRuntimeAsyncTask(RuntimeAsyncTask } } - task.InstrumentedHandleSuspended(flags, ref state); + task.InstrumentedHandleSuspended(flags); return; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void FinalizeRuntimeAsyncTask(ref RuntimeAsyncAwaitState state, RuntimeAsyncTask task) + private static void FinalizeRuntimeAsyncTask(RuntimeAsyncTask task) { if (RuntimeAsyncInstrumentationHelpers.InstrumentCheckPoint) { AsyncInstrumentation.Flags flags = AsyncInstrumentation.SyncActiveFlags(); if (flags != AsyncInstrumentation.Flags.Disabled) { - InstrumentedFinalizeRuntimeAsyncTask(task, ref state, flags); + InstrumentedFinalizeRuntimeAsyncTask(task, flags); return; } } - task.HandleSuspended(ref state); + task.HandleSuspended(); } // Change return type to RuntimeAsyncTask -- no benefit since this is used for Task returning thunks only #pragma warning disable CA1859 // When a Task-returning thunk gets a continuation result // it calls here to make a Task that awaits on the current async state. - private static Task FinalizeTaskReturningThunk(ref RuntimeAsyncAwaitState state) + private static Task FinalizeTaskReturningThunk() { RuntimeAsyncTask result = new(); - FinalizeRuntimeAsyncTask(ref state, result!); + FinalizeRuntimeAsyncTask(result!); return result; } - private static Task FinalizeTaskReturningThunk(ref RuntimeAsyncAwaitState state) + private static Task FinalizeTaskReturningThunk() { RuntimeAsyncTask result = new(); - FinalizeRuntimeAsyncTask(ref state, result!); + FinalizeRuntimeAsyncTask(result!); return result; } - private static ValueTask FinalizeValueTaskReturningThunk(ref RuntimeAsyncAwaitState state) + private static ValueTask FinalizeValueTaskReturningThunk() { // We only come to these methods in the expensive case (already // suspended), so ValueTask optimization here is not relevant. - return new ValueTask(FinalizeTaskReturningThunk(ref state)); + return new ValueTask(FinalizeTaskReturningThunk()); } - private static ValueTask FinalizeValueTaskReturningThunk(ref RuntimeAsyncAwaitState state) + private static ValueTask FinalizeValueTaskReturningThunk() { - return new ValueTask(FinalizeTaskReturningThunk(ref state)); + return new ValueTask(FinalizeTaskReturningThunk()); } private static Task TaskFromException(Exception ex) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index d5f367c6498b0b..2d9891ef57b874 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -38,22 +38,15 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me ILLocalVariable returnTaskLocal = emitter.NewLocal(returnType); - MetadataType asyncHelpersType = context.SystemModule.GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8); - TypeDesc stackStateType = asyncHelpersType.GetKnownNestedType("RuntimeAsyncStackState"u8); - ILLocalVariable stackStateLocal = emitter.NewLocal(stackStateType); - TypeDesc awaitStateType = asyncHelpersType.GetKnownNestedType("RuntimeAsyncAwaitState"u8); - ILLocalVariable refAwaitStateLocal = emitter.NewLocal(awaitStateType.MakeByRefType()); + TypeDesc executionAndSyncBlockStoreType = context.SystemModule.GetKnownType("System.Runtime.CompilerServices"u8, "ExecutionAndSyncBlockStore"u8); + ILLocalVariable executionAndSyncBlockStoreLocal = emitter.NewLocal(executionAndSyncBlockStoreType); ILCodeLabel returnTaskLabel = emitter.NewCodeLabel(); ILCodeLabel suspendedLabel = emitter.NewCodeLabel(); ILCodeLabel finishedLabel = emitter.NewCodeLabel(); - codestream.Emit(ILOpcode.ldsflda, emitter.NewToken(asyncHelpersType.GetKnownField("t_runtimeAsyncAwaitState"u8))); - codestream.EmitStLoc(refAwaitStateLocal); - - codestream.EmitLdLoc(refAwaitStateLocal); - codestream.EmitLdLoca(stackStateLocal); - codestream.Emit(ILOpcode.call, emitter.NewToken(awaitStateType.GetKnownMethod("Push"u8, null))); + codestream.EmitLdLoca(executionAndSyncBlockStoreLocal); + codestream.Emit(ILOpcode.call, emitter.NewToken(executionAndSyncBlockStoreType.GetKnownMethod("Push"u8, null))); ILExceptionRegionBuilder tryFinallyRegion = emitter.NewFinallyRegion(); { @@ -97,7 +90,9 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me codestream.EmitStLoc(logicalResultLocal); } - MethodDesc asyncCallContinuationMd = asyncHelpersType.GetKnownMethod("AsyncCallContinuation"u8, null); + MethodDesc asyncCallContinuationMd = context.SystemModule + .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) + .GetKnownMethod("AsyncCallContinuation"u8, null); codestream.Emit(ILOpcode.call, emitter.NewToken(asyncCallContinuationMd)); @@ -166,7 +161,8 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me parameters: new[] { exceptionType } ); - fromExceptionMd = asyncHelpersType + fromExceptionMd = context.SystemModule + .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) .GetKnownMethod(isValueTask ? "ValueTaskFromException"u8 : "TaskFromException"u8, fromExceptionSignature) .MakeInstantiatedMethod(new Instantiation(logicalReturnType)); } @@ -179,7 +175,8 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me parameters: new[] { exceptionType } ); - fromExceptionMd = asyncHelpersType + fromExceptionMd = context.SystemModule + .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) .GetKnownMethod(isValueTask ? "ValueTaskFromException"u8 : "TaskFromException"u8, fromExceptionSignature); } @@ -198,10 +195,11 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me MethodSignatureFlags.Static, genericParameterCount: 1, returnType: ((MetadataType)returnType.GetTypeDefinition()).MakeInstantiatedType(context.GetSignatureVariable(0, true)), - parameters: [awaitStateType.MakeByRefType()] + parameters: Array.Empty() ); - finalizeTaskReturningThunkMd = asyncHelpersType + finalizeTaskReturningThunkMd = context.SystemModule + .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) .GetKnownMethod(isValueTask ? "FinalizeValueTaskReturningThunk"u8 : "FinalizeTaskReturningThunk"u8, finalizeReturningThunkSignature) .MakeInstantiatedMethod(new Instantiation(logicalReturnType)); } @@ -211,14 +209,14 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me MethodSignatureFlags.Static, genericParameterCount: 0, returnType: returnType, - parameters: [awaitStateType.MakeByRefType()] + parameters: Array.Empty() ); - finalizeTaskReturningThunkMd = asyncHelpersType + finalizeTaskReturningThunkMd = context.SystemModule + .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) .GetKnownMethod(isValueTask ? "FinalizeValueTaskReturningThunk"u8 : "FinalizeTaskReturningThunk"u8, finalizeReturningThunkSignature); } - codestream.EmitLdLoc(refAwaitStateLocal); codestream.Emit(ILOpcode.call, emitter.NewToken(finalizeTaskReturningThunkMd)); codestream.EmitStLoc(returnTaskLocal); codestream.Emit(ILOpcode.leave, returnTaskLabel); @@ -229,8 +227,8 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me { codestream.BeginHandler(tryFinallyRegion); - codestream.EmitLdLoc(refAwaitStateLocal); - codestream.Emit(ILOpcode.call, emitter.NewToken(awaitStateType.GetKnownMethod("Pop"u8, null))); + codestream.EmitLdLoca(executionAndSyncBlockStoreLocal); + codestream.Emit(ILOpcode.call, emitter.NewToken(executionAndSyncBlockStoreType.GetKnownMethod("Pop"u8, null))); codestream.Emit(ILOpcode.endfinally); codestream.EndHandler(tryFinallyRegion); } diff --git a/src/coreclr/vm/asyncthunks.cpp b/src/coreclr/vm/asyncthunks.cpp index ef45a4a41c715d..3fa631527cf29c 100644 --- a/src/coreclr/vm/asyncthunks.cpp +++ b/src/coreclr/vm/asyncthunks.cpp @@ -93,10 +93,8 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncCallVariant, MetaSig& // Emits roughly the following code: // - // RuntimeAsyncStackState stackState; - // ref RuntimeAsyncAwaitState awaitState = ref AsyncHelpers.t_runtimeAsyncAwaitState; - // awaitState.Push(&stackState); - // + // ExecutionAndSyncBlockStore store = default; + // store.Push(); // try // { // try @@ -106,7 +104,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncCallVariant, MetaSig& // if (AsyncHelpers.AsyncCallContinuation() == null) // return Task.FromResult(result); // - // return FinalizeTaskReturningThunk(ref awaitState); + // return FinalizeTaskReturningThunk(); // } // catch (Exception ex) // { @@ -115,7 +113,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncCallVariant, MetaSig& // } // finally // { - // awaitState.Pop(); + // store.Pop(); // } ILCodeStream* pCode = pSL->NewCodeStream(ILStubLinker::kDispatch); @@ -134,24 +132,15 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncCallVariant, MetaSig& LocalDesc returnLocalDesc(thTaskRet); DWORD returnTaskLocal = pCode->NewLocal(returnLocalDesc); - - LocalDesc stackStateLocalDesc(TypeHandle(CoreLibBinder::GetClass(CLASS__RUNTIME_ASYNC_STACK_STATE))); - DWORD stackStateLocal = pCode->NewLocal(stackStateLocalDesc); - - LocalDesc refAwaitStateLocalDesc(TypeHandle(CoreLibBinder::GetClass(CLASS__RUNTIME_ASYNC_AWAIT_STATE))); - refAwaitStateLocalDesc.MakeByRef(); - DWORD refAwaitStateLocal = pCode->NewLocal(refAwaitStateLocalDesc); + LocalDesc executionAndSyncBlockStoreLocalDesc(CoreLibBinder::GetClass(CLASS__EXECUTIONANDSYNCBLOCKSTORE)); + DWORD executionAndSyncBlockStoreLocal = pCode->NewLocal(executionAndSyncBlockStoreLocalDesc); ILCodeLabel* returnTaskLabel = pCode->NewCodeLabel(); ILCodeLabel* suspendedLabel = pCode->NewCodeLabel(); ILCodeLabel* finishedLabel = pCode->NewCodeLabel(); - pCode->EmitLDSFLDA(pCode->GetToken(CoreLibBinder::GetField(FIELD__ASYNC_HELPERS__TLS_RUNTIME_ASYNC_AWAIT_STATE))); - pCode->EmitSTLOC(refAwaitStateLocal); - - pCode->EmitLDLOC(refAwaitStateLocal); - pCode->EmitLDLOCA(stackStateLocal); - pCode->EmitCALL(METHOD__RUNTIME_ASYNC_AWAIT_STATE__PUSH, 2, 0); + pCode->EmitLDLOCA(executionAndSyncBlockStoreLocal); + pCode->EmitCALL(pCode->GetToken(CoreLibBinder::GetMethod(METHOD__EXECUTIONANDSYNCBLOCKSTORE__PUSH)), 1, 0); { pCode->BeginTryBlock(); @@ -263,8 +252,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncCallVariant, MetaSig& md = CoreLibBinder::GetMethod(METHOD__ASYNC_HELPERS__FINALIZE_TASK_RETURNING_THUNK); finalizeTaskReturningThunkToken = pCode->GetToken(md); } - pCode->EmitLDLOC(refAwaitStateLocal); - pCode->EmitCALL(finalizeTaskReturningThunkToken, 1, 1); + pCode->EmitCALL(finalizeTaskReturningThunkToken, 0, 1); pCode->EmitSTLOC(returnTaskLocal); pCode->EmitLEAVE(returnTaskLabel); @@ -273,8 +261,8 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncCallVariant, MetaSig& // { pCode->BeginFinallyBlock(); - pCode->EmitLDLOC(refAwaitStateLocal); - pCode->EmitCALL(METHOD__RUNTIME_ASYNC_AWAIT_STATE__POP, 1, 0); + pCode->EmitLDLOCA(executionAndSyncBlockStoreLocal); + pCode->EmitCALL(pCode->GetToken(CoreLibBinder::GetMethod(METHOD__EXECUTIONANDSYNCBLOCKSTORE__POP)), 1, 0); pCode->EmitENDFINALLY(); pCode->EndFinallyBlock(); } diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 674942ce365a61..f75fdcce0c832d 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -683,6 +683,10 @@ DEFINE_CLASS(RESOURCE_MANAGER, Resources, ResourceManager) DEFINE_CLASS(RTFIELD, Reflection, RtFieldInfo) DEFINE_METHOD(RTFIELD, GET_FIELDESC, GetFieldDesc, IM_RetIntPtr) +DEFINE_CLASS(EXECUTIONANDSYNCBLOCKSTORE, CompilerServices, ExecutionAndSyncBlockStore) +DEFINE_METHOD(EXECUTIONANDSYNCBLOCKSTORE, PUSH, Push, NoSig) +DEFINE_METHOD(EXECUTIONANDSYNCBLOCKSTORE, POP, Pop, NoSig) + DEFINE_CLASS(RUNTIME_HELPERS, CompilerServices, RuntimeHelpers) DEFINE_METHOD(RUNTIME_HELPERS, IS_BITWISE_EQUATABLE, IsBitwiseEquatable, NoSig) DEFINE_METHOD(RUNTIME_HELPERS, GET_RAW_DATA, GetRawData, NoSig) @@ -707,10 +711,10 @@ DEFINE_METHOD(ASYNC_HELPERS, ALLOC_CONTINUATION, AllocContinuation, DEFINE_METHOD(ASYNC_HELPERS, ALLOC_CONTINUATION_METHOD, AllocContinuationMethod, NoSig) DEFINE_METHOD(ASYNC_HELPERS, ALLOC_CONTINUATION_CLASS, AllocContinuationClass, NoSig) -DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_TASK_RETURNING_THUNK, FinalizeTaskReturningThunk, SM_RefRuntimeAsyncAwaitState_RetTask) -DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_TASK_RETURNING_THUNK_1, FinalizeTaskReturningThunk, GM_RefRuntimeAsyncAwaitState_RetTaskOfT) -DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_VALUETASK_RETURNING_THUNK, FinalizeValueTaskReturningThunk, SM_RefRuntimeAsyncAwaitState_RetValueTask) -DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_VALUETASK_RETURNING_THUNK_1, FinalizeValueTaskReturningThunk, GM_RefRuntimeAsyncAwaitState_RetValueTaskOfT) +DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_TASK_RETURNING_THUNK, FinalizeTaskReturningThunk, SM_RetTask) +DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_TASK_RETURNING_THUNK_1, FinalizeTaskReturningThunk, GM_RetTaskOfT) +DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_VALUETASK_RETURNING_THUNK, FinalizeValueTaskReturningThunk, SM_RetValueTask) +DEFINE_METHOD(ASYNC_HELPERS, FINALIZE_VALUETASK_RETURNING_THUNK_1, FinalizeValueTaskReturningThunk, GM_RetValueTaskOfT) DEFINE_METHOD(ASYNC_HELPERS, TASK_FROM_EXCEPTION, TaskFromException, SM_Exception_RetTask) DEFINE_METHOD(ASYNC_HELPERS, TASK_FROM_EXCEPTION_1, TaskFromException, GM_Exception_RetTaskOfT) @@ -728,18 +732,11 @@ DEFINE_METHOD(ASYNC_HELPERS, RESTORE_CONTEXTS, RestoreContexts, No DEFINE_METHOD(ASYNC_HELPERS, RESTORE_CONTEXTS_ON_SUSPENSION, RestoreContextsOnSuspension, NoSig) DEFINE_METHOD(ASYNC_HELPERS, ASYNC_CALL_CONTINUATION, AsyncCallContinuation, NoSig) DEFINE_METHOD(ASYNC_HELPERS, TAIL_AWAIT, TailAwait, NoSig) -DEFINE_FIELD(ASYNC_HELPERS, TLS_RUNTIME_ASYNC_AWAIT_STATE, t_runtimeAsyncAwaitState) #ifdef FEATURE_INTERPRETER DEFINE_METHOD(ASYNC_HELPERS, RESUME_INTERPRETER_CONTINUATION, ResumeInterpreterContinuation, NoSig) #endif -DEFINE_CLASS(RUNTIME_ASYNC_AWAIT_STATE, CompilerServices, AsyncHelpers+RuntimeAsyncAwaitState) -DEFINE_METHOD(RUNTIME_ASYNC_AWAIT_STATE, PUSH, Push, NoSig) -DEFINE_METHOD(RUNTIME_ASYNC_AWAIT_STATE, POP, Pop, NoSig) - -DEFINE_CLASS(RUNTIME_ASYNC_STACK_STATE, CompilerServices, AsyncHelpers+RuntimeAsyncStackState) - DEFINE_CLASS_U(CompilerServices, Continuation, ContinuationObject) DEFINE_FIELD_U(Next, ContinuationObject, Next) DEFINE_FIELD_U(ResumeInfo, ContinuationObject, ResumeInfo) @@ -981,11 +978,11 @@ DEFINE_FIELD(EXECUTIONCONTEXT, DEFAULT_FLOW_SUPPRESSED, DefaultFlowSu DEFINE_CLASS(DIRECTONTHREADLOCALDATA, Threading, Thread+DirectOnThreadLocalData) DEFINE_CLASS(THREAD, Threading, Thread) -DEFINE_METHOD(THREAD, START_CALLBACK, StartCallback, SM_PtrThread_RetVoid) +DEFINE_METHOD(THREAD, START_CALLBACK, StartCallback, SM_PtrThread_RetVoid) DEFINE_METHOD(THREAD, POLLGC, PollGC, NoSig) DEFINE_METHOD(THREAD, ON_THREAD_EXITING, OnThreadExited, SM_PtrThread_PtrException_RetVoid) #ifdef FOR_ILLINK -DEFINE_METHOD(THREAD, CTOR, .ctor, IM_RetVoid) +DEFINE_METHOD(THREAD, CTOR, .ctor, IM_RetVoid) #endif // FOR_ILLINK #ifdef FEATURE_OBJCMARSHAL diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index d304d63ff9d908..0d631bf34b4db0 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -547,10 +547,8 @@ DEFINE_METASIG(SM(PtrByte_RetStr, P(b), s)) DEFINE_METASIG(SM(Str_RetPtrByte, s, P(b))) DEFINE_METASIG(SM(PtrByte_RetVoid, P(b), v)) -DEFINE_METASIG_T(SM(RefRuntimeAsyncAwaitState_RetTask, r(g(RUNTIME_ASYNC_AWAIT_STATE)), C(TASK))) -DEFINE_METASIG_T(SM(RefRuntimeAsyncAwaitState_RetValueTask, r(g(RUNTIME_ASYNC_AWAIT_STATE)), g(VALUETASK))) -DEFINE_METASIG_T(GM(RefRuntimeAsyncAwaitState_RetTaskOfT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, r(g(RUNTIME_ASYNC_AWAIT_STATE)), GI(C(TASK_1), 1, M(0)))) -DEFINE_METASIG_T(GM(RefRuntimeAsyncAwaitState_RetValueTaskOfT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, r(g(RUNTIME_ASYNC_AWAIT_STATE)), GI(g(VALUETASK_1), 1, M(0)))) +DEFINE_METASIG_T(GM(RetTaskOfT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, , GI(C(TASK_1), 1, M(0)))) +DEFINE_METASIG_T(GM(RetValueTaskOfT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, , GI(g(VALUETASK_1), 1, M(0)))) // Undefine macros in case we include the file again in the compilation unit diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs index 510b863d4dda8e..0d5ff2b7ca8143 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs @@ -25,11 +25,14 @@ public static partial class AsyncHelpers [BypassReadyToRun] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.Async)] [StackTraceHidden] - public static unsafe void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : INotifyCompletion + public static void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : INotifyCompletion { ref RuntimeAsyncAwaitState state = ref t_runtimeAsyncAwaitState; - Continuation? sentinelContinuation = state.SentinelContinuation ??= new Continuation(); - state.StackState->Notifier = awaiter; + Continuation? sentinelContinuation = state.SentinelContinuation; + if (sentinelContinuation == null) + state.SentinelContinuation = sentinelContinuation = new Continuation(); + + state.Notifier = awaiter; state.CaptureContexts(); AsyncSuspend(sentinelContinuation); } @@ -45,11 +48,14 @@ public static unsafe void AwaitAwaiter(TAwaiter awaiter) where TAwaite [BypassReadyToRun] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.Async)] [StackTraceHidden] - public static unsafe void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion + public static void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion { ref RuntimeAsyncAwaitState state = ref t_runtimeAsyncAwaitState; - Continuation? sentinelContinuation = state.SentinelContinuation ??= new Continuation(); - state.StackState->CriticalNotifier = awaiter; + Continuation? sentinelContinuation = state.SentinelContinuation; + if (sentinelContinuation == null) + state.SentinelContinuation = sentinelContinuation = new Continuation(); + + state.CriticalNotifier = awaiter; state.CaptureContexts(); AsyncSuspend(sentinelContinuation); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs index 6172fe6fdf295c..5bfcc075bb5d13 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs @@ -89,7 +89,7 @@ CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out try { Guid iidMetaDataImport = typeof(IMetaDataImport).GUID; - if (_legacyModulePointer != 0 && Marshal.QueryInterface(_legacyModulePointer, iidMetaDataImport, out nint ppMdi) >= 0) + if (_legacyModulePointer != 0 && _legacyModulePointer != 1 && Marshal.QueryInterface(_legacyModulePointer, iidMetaDataImport, out nint ppMdi) >= 0) { legacyImport = ComInterfaceMarshaller.ConvertToManaged((void*)ppMdi); Marshal.Release(ppMdi);