Repository: dotnet/runtime
File: src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs (C#)

Code before:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using Internal.TypeSystem;
using System.Collections.Generic;
using System.Diagnostics;
using Internal.TypeSystem.Ecma;
using ILCompiler;

#nullable enable

namespace Internal.IL.Stubs
{
    public static class AsyncThunkILEmitter
    {
        private enum AsyncHelper
        {
            ExecutionAndSyncBlockStore,
            ExecutionAndSyncBlockStore_Push,
            ExecutionAndSyncBlockStore_Pop,

            AsyncHelpers,

            AsyncHelpers_AsyncCallContinuation,
            AsyncHelpers_TransparentAwait,
            AsyncHelpers_CompletedTask,
            AsyncHelpers_CompletedTaskResult,

            AsyncHelpers_TaskFromException,
            AsyncHelpers_TaskFromException_1,
            AsyncHelpers_ValueTaskFromException,
            AsyncHelpers_ValueTaskFromException_1,

            AsyncHelpers_FinalizeTaskReturningThunk,
            AsyncHelpers_FinalizeTaskReturningThunk_1,
            AsyncHelpers_FinalizeValueTaskReturningThunk,
            AsyncHelpers_FinalizeValueTaskReturningThunk_1,

            Task,
            Task_1,
            ValueTask,

Review comment (refactor):
We should not be building the managed helpers support as async-specific. It should be usable for any situation we need to encode a call to managed method, like `Environment.CurrentManagedThreadId` mentioned in https://github.com/dotnet/runtime/pull/121679#issuecomment-3538229885

Code after:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using Internal.TypeSystem;

namespace Internal.IL.Stubs
{
    public static class AsyncThunkILEmitter
    {
        // Emits a thunk that wraps an async method to return a Task or ValueTask.
        // The thunk calls the async method, and if it completes synchronously,
        // it returns a completed Task/ValueTask. If the async method suspends,
        // it calls FinalizeTaskReturningThunk/FinalizeValueTaskReturningThunk method to get the Task/ValueTask.

        // The emitted code matches method EmitTaskReturningThunk in CoreCLR VM.
        public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, MethodDesc asyncMethod)
        {
            TypeSystemContext context = taskReturningMethod.Context;

            var emitter = new ILEmitter();
            var codestream = emitter.NewCodeStream();

            MethodSignature sig = taskReturningMethod.Signature;
            TypeDesc returnType = sig.ReturnType;

            bool isValueTask = returnType.IsValueType;

            TypeDesc logicalReturnType = null;
            ILLocalVariable logicalResultLocal = 0;
            if (returnType.HasInstantiation)
            {
                // The return type is either Task<T> or ValueTask<T>, exactly one generic argument
                logicalReturnType = returnType.Instantiation[0];
                logicalResultLocal = emitter.NewLocal(logicalReturnType);
            }

            ILLocalVariable returnTaskLocal = emitter.NewLocal(returnType);

            TypeDesc executionAndSyncBlockStoreType = context.SystemModule.GetKnownType("System.Runtime.CompilerServices"u8, "ExecutionAndSyncBlockStore"u8);
            ILLocalVariable executionAndSyncBlockStoreLocal = emitter.NewLocal(executionAndSyncBlockStoreType);