From f62725f86452eec3ef2b1307215efd9e62c68d25 Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Thu, 6 Nov 2025 19:57:53 -0800 Subject: [PATCH 01/13] Update EmitTaskReturningThunk in Native AOT --- .../Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 240 +++++++++++++++++- .../Common/TypeSystem/IL/Stubs/ILEmitter.cs | 28 +- src/coreclr/vm/asyncthunks.cpp | 5 +- 3 files changed, 259 insertions(+), 14 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index 0f048327cfdc4d..86e6ebbd143b4e 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -1,12 +1,14 @@ // 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 { + // The emitted code matches method EmitTaskReturningThunk in CoreCLR VM. public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, MethodDesc asyncMethod) { TypeSystemContext context = taskReturningMethod.Context; @@ -14,24 +16,242 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me var emitter = new ILEmitter(); var codestream = emitter.NewCodeStream(); - // TODO: match EmitTaskReturningThunk in CoreCLR VM - MethodSignature sig = asyncMethod.Signature; - int numParams = (sig.IsStatic || sig.IsExplicitThis) ? sig.Length : sig.Length + 1; - for (int i = 0; i < numParams; i++) - codestream.EmitLdArg(i); + TypeDesc returnType = sig.ReturnType; + + MetadataType md = taskReturningMethod.Signature.ReturnType as MetadataType; + ReadOnlySpan name = md.Name; + bool isValueTask = name.SequenceEqual("ValueTask"u8) || name.SequenceEqual("ValueTask`1"u8); + + TypeDesc logicalReturnType = null; + ILLocalVariable logicalResultLocal = 0; + if (returnType.HasInstantiation) + { + // The return type is either Task or ValueTask, exactly one generic argument + logicalReturnType = returnType.Instantiation[0]; + logicalResultLocal = emitter.NewLocal(logicalReturnType); + } + + ILLocalVariable returnTaskLocal = emitter.NewLocal(returnType); + + // TODO: Fix this (ExecutionAndSyncBlockStore is not available in Native AOT). + + // 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.call, emitter.NewToken(asyncMethod)); + // codestream.EmitLdLoca(executionAndSyncBlockStoreLocal); + // codestream.Emit(ILOpcode.call, emitter.NewToken(executionAndSyncBlockStoreType.GetKnownMethod("Push"u8, null))); - if (sig.ReturnType.IsVoid) + ILExceptionRegionBuilder tryFinallyRegion = emitter.NewFinallyRegion(); { - codestream.Emit(ILOpcode.call, emitter.NewToken(context.SystemModule.GetKnownType("System.Threading.Tasks"u8, "Task"u8).GetKnownMethod("get_CompletedTask"u8, null))); + codestream.BeginTry(tryFinallyRegion); + codestream.Emit(ILOpcode.nop); + ILExceptionRegionBuilder tryCatchRegion = emitter.NewCatchRegion(); + { + codestream.BeginTry(tryCatchRegion); + + int localArg = 0; + if (sig.IsExplicitThis) + { + codestream.EmitLdArg(localArg++); + } + + for (int iArg = 0; iArg < sig.Length; iArg++) + { + codestream.EmitLdArg(localArg++); + } + + if (asyncMethod.OwningType.HasInstantiation) + { + var inst = new TypeDesc[asyncMethod.OwningType.Instantiation.Length]; + for (int i = 0; i < inst.Length; i++) + { + inst[i] = context.GetSignatureVariable(i, false); + } + + var instantiatedType = context.GetInstantiatedType((MetadataType)asyncMethod.OwningType, new Instantiation(inst)); + asyncMethod = context.GetMethodForInstantiatedType(asyncMethod, instantiatedType); + } + + if (asyncMethod.HasInstantiation) + { + var inst = new TypeDesc[asyncMethod.Instantiation.Length]; + for (int i = 0; i < inst.Length; i++) + { + inst[i] = context.GetSignatureVariable(i, true); + } + asyncMethod = asyncMethod.MakeInstantiatedMethod(new Instantiation(inst)); + } + + codestream.Emit(ILOpcode.call, emitter.NewToken(asyncMethod)); + + if (logicalReturnType != null) + { + codestream.EmitStLoc(logicalResultLocal); + } + + // TODO: Fix this (AsyncCallContinuation is not available in Native AOT). + + //MethodDesc asyncCallContinuationMd = context.SystemModule + // .GetKnownType("System.StubHelpers"u8, "StubHelpers"u8) + // .GetKnownMethod("AsyncCallContinuation"u8, null); + + //codestream.Emit(ILOpcode.call, emitter.NewToken(asyncCallContinuationMd)); + + codestream.Emit(ILOpcode.brfalse, finishedLabel); + codestream.Emit(ILOpcode.leave, suspendedLabel); + codestream.EmitLabel(finishedLabel); + + if (logicalReturnType != null) + { + codestream.EmitLdLoc(logicalResultLocal); + + MethodDesc fromResultMethod; + if (isValueTask) + { + fromResultMethod = context.SystemModule + .GetKnownType("System.Threading.Tasks"u8, "ValueTask`1"u8) + .GetKnownMethod("FromResult"u8, null) + .MakeInstantiatedMethod(new Instantiation(logicalReturnType)); + } + else + { + fromResultMethod = context.SystemModule + .GetKnownType("System.Threading.Tasks"u8, "Task"u8) + .GetKnownMethod("FromResult"u8, null) + .MakeInstantiatedMethod(new Instantiation(logicalReturnType)); + } + + codestream.Emit(ILOpcode.call, emitter.NewToken(fromResultMethod)); + } + else + { + MethodDesc getCompletedTaskMethod; + if (isValueTask) + { + getCompletedTaskMethod = context.SystemModule + .GetKnownType("System.Threading.Tasks"u8, "ValueTask"u8) + .GetKnownMethod("get_CompletedTask"u8, null); + } + else + { + getCompletedTaskMethod = context.SystemModule + .GetKnownType("System.Threading.Tasks"u8, "Task"u8) + .GetKnownMethod("get_CompletedTask"u8, null); + } + codestream.Emit(ILOpcode.call, emitter.NewToken(getCompletedTaskMethod)); + } + + codestream.EmitLdLoc(returnTaskLocal); + codestream.Emit(ILOpcode.leave, returnTaskLabel); + + codestream.EndTry(tryCatchRegion); + } + // Catch + { + codestream.BeginHandler(tryCatchRegion); + + MethodDesc fromExceptionMd; + if (logicalReturnType != null) + { + // Generate: returnType.FromException(Exception) + if (isValueTask) + { + fromExceptionMd = context.SystemModule + .GetKnownType("System.Threading.Tasks"u8, "ValueTask`1"u8) + .GetKnownMethod("FromException"u8, null); + } + else + { + fromExceptionMd = context.SystemModule + .GetKnownType("System.Threading.Tasks"u8, "Task`1"u8) + .GetKnownMethod("FromException"u8, null); + } + fromExceptionMd = fromExceptionMd.MakeInstantiatedMethod(new Instantiation(logicalReturnType)); + } + else + { + // Generate: returnType.FromException(Exception) + if (isValueTask) + { + fromExceptionMd = context.SystemModule + .GetKnownType("System.Threading.Tasks"u8, "ValueTask"u8) + .GetKnownMethod("FromException"u8, null); + } + else + { + fromExceptionMd = context.SystemModule + .GetKnownType("System.Threading.Tasks"u8, "Task"u8) + .GetKnownMethod("FromException"u8, null); + } + } + + codestream.Emit(ILOpcode.call, emitter.NewToken(fromExceptionMd)); + codestream.EmitStLoc(returnTaskLocal); + codestream.Emit(ILOpcode.leave, returnTaskLabel); + codestream.EndHandler(tryCatchRegion); + } + + codestream.EmitLabel(suspendedLabel); + + // TODO: Fix this (Finalize returning thunks are not available in Native AOT). + + //MethodDesc finalizeTaskReturningThunkMd; + + //if (logicalReturnType != null) + //{ + // if (isValueTask) + // { + // finalizeTaskReturningThunkMd = context.SystemModule + // .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) + // .GetKnownMethod("FinalizeValueTaskReturningThunk`1"u8, null); + // } + // else + // { + // finalizeTaskReturningThunkMd = context.SystemModule + // .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) + // .GetKnownMethod("FinalizeTaskReturningThunk`1"u8, null); + // } + // finalizeTaskReturningThunkMd = finalizeTaskReturningThunkMd.MakeInstantiatedMethod(new Instantiation(logicalReturnType)); + //} + //else + //{ + // if (isValueTask) + // { + // finalizeTaskReturningThunkMd = context.SystemModule + // .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) + // .GetKnownMethod("FinalizeValueTaskReturningThunk"u8, null); + // } + // else + // { + // finalizeTaskReturningThunkMd = context.SystemModule + // .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) + // .GetKnownMethod("FinalizeTaskReturningThunk"u8, null); + // } + //} + //codestream.Emit(ILOpcode.call, emitter.NewToken(finalizeTaskReturningThunkMd)); + codestream.EmitStLoc(returnTaskLocal); + codestream.Emit(ILOpcode.leave, returnTaskLabel); + + codestream.EndTry(tryFinallyRegion); } - else + // { - codestream.Emit(ILOpcode.call, emitter.NewToken(context.SystemModule.GetKnownType("System.Threading.Tasks"u8, "Task"u8).GetKnownMethod("FromResult"u8, null).MakeInstantiatedMethod(sig.ReturnType))); + codestream.BeginHandler(tryFinallyRegion); + + // TODO: Fix this (ExecutionAndSyncBlockStore is not available in Native AOT). + + // codestream.EmitLdLoca(executionAndSyncBlockStoreLocal); + // codestream.Emit(ILOpcode.call, emitter.NewToken(executionAndSyncBlockStoreType.GetKnownMethod("Pop"u8, null))); + codestream.EndHandler(tryFinallyRegion); } + codestream.EmitLabel(returnTaskLabel); + codestream.EmitLdLoc(returnTaskLocal); codestream.Emit(ILOpcode.ret); return emitter.Link(taskReturningMethod); diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs index 3625b6397f5d85..bfffd099ee60b3 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs @@ -669,6 +669,7 @@ public class ILEmitter private ArrayBuilder _codeStreams; private ArrayBuilder _locals; private ArrayBuilder _tokens; + private ArrayBuilder _catchRegions; private ArrayBuilder _finallyRegions; public ILEmitter() @@ -727,6 +728,14 @@ public ILCodeLabel NewCodeLabel() return newLabel; } + // For now, only catches exceptions of type Exception. + public ILExceptionRegionBuilder NewCatchRegion() + { + var region = new ILExceptionRegionBuilder(); + _catchRegions.Add(region); + return region; + } + public ILExceptionRegionBuilder NewFinallyRegion() { var region = new ILExceptionRegionBuilder(); @@ -782,18 +791,33 @@ public MethodIL Link(MethodDesc owningMethod) ILExceptionRegion[] exceptionRegions = null; - int numberOfExceptionRegions = _finallyRegions.Count; + int numberOfExceptionRegions = _catchRegions.Count + _finallyRegions.Count; if (numberOfExceptionRegions > 0) { exceptionRegions = new ILExceptionRegion[numberOfExceptionRegions]; + TypeDesc exceptionType = owningMethod.Context.SystemModule.GetKnownType("System"u8, "Exception"u8); + + int exceptionTypeToken = (int)NewToken(exceptionType); + + for (int i = 0; i < _catchRegions.Count; i++) + { + ILExceptionRegionBuilder region = _catchRegions[i]; + + Debug.Assert(region.IsDefined); + + exceptionRegions[i] = new ILExceptionRegion(ILExceptionRegionKind.Catch, + region.TryOffset, region.TryLength, region.HandlerOffset, region.HandlerLength, + classToken: exceptionTypeToken, filterOffset: 0); + } + for (int i = 0; i < _finallyRegions.Count; i++) { ILExceptionRegionBuilder region = _finallyRegions[i]; Debug.Assert(region.IsDefined); - exceptionRegions[i] = new ILExceptionRegion(ILExceptionRegionKind.Finally, + exceptionRegions[_catchRegions.Count + i] = new ILExceptionRegion(ILExceptionRegionKind.Finally, region.TryOffset, region.TryLength, region.HandlerOffset, region.HandlerLength, classToken: 0, filterOffset: 0); } diff --git a/src/coreclr/vm/asyncthunks.cpp b/src/coreclr/vm/asyncthunks.cpp index fcb0c06d059936..559d2d60230723 100644 --- a/src/coreclr/vm/asyncthunks.cpp +++ b/src/coreclr/vm/asyncthunks.cpp @@ -58,7 +58,8 @@ bool MethodDesc::TryGenerateAsyncThunk(DynamicResolver** resolver, COR_ILMETHOD_ return true; } -// provided an async method, emits a Task-returning wrapper. +// Provided an async method, emits a Task-returning wrapper. +// The emitted code matches method EmitTaskReturningThunk in the Managed Type System. void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig& thunkMsig, ILStubLinker* pSL) { _ASSERTE(!pAsyncOtherVariant->IsAsyncThunkMethod()); @@ -132,7 +133,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig& } int token; - _ASSERTE(!pAsyncOtherVariant->IsWrapperStub()); + _ASSERTE(!pAsyncOtherVariant->IsWrapperStub()); // Would it be better to move the assertion to the top of this method? if (pAsyncOtherVariant->HasClassOrMethodInstantiation()) { // For generic code emit generic signatures. From 44f757f408ba6db5bb543e0a160400972f8fc95d Mon Sep 17 00:00:00 2001 From: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:07:46 -0800 Subject: [PATCH 02/13] Update src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michal Strehovský --- src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index 86e6ebbd143b4e..4db9af5ac0f1a8 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -19,9 +19,7 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me MethodSignature sig = asyncMethod.Signature; TypeDesc returnType = sig.ReturnType; - MetadataType md = taskReturningMethod.Signature.ReturnType as MetadataType; - ReadOnlySpan name = md.Name; - bool isValueTask = name.SequenceEqual("ValueTask"u8) || name.SequenceEqual("ValueTask`1"u8); + bool isValueTask = returnType.IsValueType; TypeDesc logicalReturnType = null; ILLocalVariable logicalResultLocal = 0; From 960be0aeb3477694bdfeae2aba35424a29d0324a Mon Sep 17 00:00:00 2001 From: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:08:00 -0800 Subject: [PATCH 03/13] Update src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michal Strehovský --- src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index 4db9af5ac0f1a8..c156d6a364e2f7 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -53,7 +53,7 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me codestream.BeginTry(tryCatchRegion); int localArg = 0; - if (sig.IsExplicitThis) + if (!sig.IsStatic) { codestream.EmitLdArg(localArg++); } From 745f01d7c74039f3190fd932bdad80b18dfec4be Mon Sep 17 00:00:00 2001 From: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:08:56 -0800 Subject: [PATCH 04/13] Update src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michal Strehovský --- src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index c156d6a364e2f7..d35e675b8409f2 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -144,7 +144,7 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me codestream.Emit(ILOpcode.call, emitter.NewToken(getCompletedTaskMethod)); } - codestream.EmitLdLoc(returnTaskLocal); + codestream.EmitStLoc(returnTaskLocal); codestream.Emit(ILOpcode.leave, returnTaskLabel); codestream.EndTry(tryCatchRegion); From 2f1cbd3dc4734f3f9bf28271fd0eb921839dffed Mon Sep 17 00:00:00 2001 From: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:09:47 -0800 Subject: [PATCH 05/13] Update src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michal Strehovský --- src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index d35e675b8409f2..ebd4cea8e9ec13 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -160,7 +160,7 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me if (isValueTask) { fromExceptionMd = context.SystemModule - .GetKnownType("System.Threading.Tasks"u8, "ValueTask`1"u8) + .GetKnownType("System.Threading.Tasks"u8, "ValueTask"u8) .GetKnownMethod("FromException"u8, null); } else From df40ec47933a6a1cf4fe439f086ee56ad4087657 Mon Sep 17 00:00:00 2001 From: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:09:56 -0800 Subject: [PATCH 06/13] Update src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michal Strehovský --- src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index ebd4cea8e9ec13..401974d913a9ff 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -166,7 +166,7 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me else { fromExceptionMd = context.SystemModule - .GetKnownType("System.Threading.Tasks"u8, "Task`1"u8) + .GetKnownType("System.Threading.Tasks"u8, "Task"u8) .GetKnownMethod("FromException"u8, null); } fromExceptionMd = fromExceptionMd.MakeInstantiatedMethod(new Instantiation(logicalReturnType)); From 0f3719bc6059502a087ac1663122d2b9d693c5e9 Mon Sep 17 00:00:00 2001 From: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:10:27 -0800 Subject: [PATCH 07/13] Update src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michal Strehovský --- src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index 401974d913a9ff..1b3c71a17d9aa2 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -245,6 +245,7 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me // codestream.EmitLdLoca(executionAndSyncBlockStoreLocal); // codestream.Emit(ILOpcode.call, emitter.NewToken(executionAndSyncBlockStoreType.GetKnownMethod("Pop"u8, null))); + codestream.Emit(ILOpcode.endfinally); codestream.EndHandler(tryFinallyRegion); } From af508ff3cf35b93833da54c8915f94cce9650db7 Mon Sep 17 00:00:00 2001 From: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:10:35 -0800 Subject: [PATCH 08/13] Update src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michal Strehovský --- src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index 1b3c71a17d9aa2..d663be84256cec 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -16,7 +16,7 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me var emitter = new ILEmitter(); var codestream = emitter.NewCodeStream(); - MethodSignature sig = asyncMethod.Signature; + MethodSignature sig = taskReturningMethod.Signature; TypeDesc returnType = sig.ReturnType; bool isValueTask = returnType.IsValueType; From c10f45891d6edb235410e27682f968a94698c34d Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Mon, 10 Nov 2025 16:44:03 -0800 Subject: [PATCH 09/13] Address PR feedback --- .../src/System.Private.CoreLib.csproj | 1 + .../src/System/StubHelpers.NativeAot.cs | 10 ++ .../Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 132 +++++++----------- .../Common/TypeSystem/IL/Stubs/ILEmitter.cs | 54 +++---- src/coreclr/vm/asyncthunks.cpp | 2 +- 5 files changed, 93 insertions(+), 106 deletions(-) create mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/StubHelpers.NativeAot.cs diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 01e53975c4819b..b5329c522da12c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -244,6 +244,7 @@ + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/StubHelpers.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/StubHelpers.NativeAot.cs new file mode 100644 index 00000000000000..a20f3186b4d27b --- /dev/null +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/StubHelpers.NativeAot.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.StubHelpers +{ + internal static partial class StubHelpers + { + internal static object? AsyncCallContinuation() => throw new Exception(); // Unconditionally expanded intrinsic + } +} diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index d663be84256cec..2d6986ee3fce86 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -8,6 +8,11 @@ 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) { @@ -32,23 +37,24 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me ILLocalVariable returnTaskLocal = emitter.NewLocal(returnType); - // TODO: Fix this (ExecutionAndSyncBlockStore is not available in Native AOT). + // TODO: Check if store/restore is responsibility of the async callee + // after https://github.com/dotnet/runtime/pull/121448 gets merged. - // TypeDesc executionAndSyncBlockStoreType = context.SystemModule.GetKnownType("System.Runtime.CompilerServices"u8, "ExecutionAndSyncBlockStore"u8); - // ILLocalVariable executionAndSyncBlockStoreLocal = emitter.NewLocal(executionAndSyncBlockStoreType); + 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.EmitLdLoca(executionAndSyncBlockStoreLocal); - // codestream.Emit(ILOpcode.call, emitter.NewToken(executionAndSyncBlockStoreType.GetKnownMethod("Push"u8, null))); + codestream.EmitLdLoca(executionAndSyncBlockStoreLocal); + codestream.Emit(ILOpcode.call, emitter.NewToken(executionAndSyncBlockStoreType.GetKnownMethod("Push"u8, null))); ILExceptionRegionBuilder tryFinallyRegion = emitter.NewFinallyRegion(); { codestream.BeginTry(tryFinallyRegion); codestream.Emit(ILOpcode.nop); - ILExceptionRegionBuilder tryCatchRegion = emitter.NewCatchRegion(); + ILExceptionRegionBuilder tryCatchRegion = emitter.NewCatchRegion(context.GetWellKnownType(WellKnownType.Object)); { codestream.BeginTry(tryCatchRegion); @@ -92,13 +98,12 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me codestream.EmitStLoc(logicalResultLocal); } - // TODO: Fix this (AsyncCallContinuation is not available in Native AOT). + MethodDesc asyncCallContinuationMd = context.SystemModule + .GetKnownType("System.StubHelpers"u8, "StubHelpers"u8) + .GetKnownMethod("AsyncCallContinuation"u8, null); - //MethodDesc asyncCallContinuationMd = context.SystemModule - // .GetKnownType("System.StubHelpers"u8, "StubHelpers"u8) - // .GetKnownMethod("AsyncCallContinuation"u8, null); + codestream.Emit(ILOpcode.call, emitter.NewToken(asyncCallContinuationMd)); - //codestream.Emit(ILOpcode.call, emitter.NewToken(asyncCallContinuationMd)); codestream.Emit(ILOpcode.brfalse, finishedLabel); codestream.Emit(ILOpcode.leave, suspendedLabel); @@ -154,38 +159,22 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me codestream.BeginHandler(tryCatchRegion); MethodDesc fromExceptionMd; - if (logicalReturnType != null) + if (isValueTask) { - // Generate: returnType.FromException(Exception) - if (isValueTask) - { - fromExceptionMd = context.SystemModule - .GetKnownType("System.Threading.Tasks"u8, "ValueTask"u8) - .GetKnownMethod("FromException"u8, null); - } - else - { - fromExceptionMd = context.SystemModule - .GetKnownType("System.Threading.Tasks"u8, "Task"u8) - .GetKnownMethod("FromException"u8, null); - } - fromExceptionMd = fromExceptionMd.MakeInstantiatedMethod(new Instantiation(logicalReturnType)); + fromExceptionMd = context.SystemModule + .GetKnownType("System.Threading.Tasks"u8, "ValueTask"u8) + .GetKnownMethod("FromException"u8, null); } else { - // Generate: returnType.FromException(Exception) - if (isValueTask) - { - fromExceptionMd = context.SystemModule - .GetKnownType("System.Threading.Tasks"u8, "ValueTask"u8) - .GetKnownMethod("FromException"u8, null); - } - else - { - fromExceptionMd = context.SystemModule - .GetKnownType("System.Threading.Tasks"u8, "Task"u8) - .GetKnownMethod("FromException"u8, null); - } + fromExceptionMd = context.SystemModule + .GetKnownType("System.Threading.Tasks"u8, "Task"u8) + .GetKnownMethod("FromException"u8, null); + } + + if (logicalReturnType != null) + { + fromExceptionMd = fromExceptionMd.MakeInstantiatedMethod(new Instantiation(logicalReturnType)); } codestream.Emit(ILOpcode.call, emitter.NewToken(fromExceptionMd)); @@ -196,55 +185,38 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me codestream.EmitLabel(suspendedLabel); - // TODO: Fix this (Finalize returning thunks are not available in Native AOT). - - //MethodDesc finalizeTaskReturningThunkMd; - - //if (logicalReturnType != null) - //{ - // if (isValueTask) - // { - // finalizeTaskReturningThunkMd = context.SystemModule - // .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) - // .GetKnownMethod("FinalizeValueTaskReturningThunk`1"u8, null); - // } - // else - // { - // finalizeTaskReturningThunkMd = context.SystemModule - // .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) - // .GetKnownMethod("FinalizeTaskReturningThunk`1"u8, null); - // } - // finalizeTaskReturningThunkMd = finalizeTaskReturningThunkMd.MakeInstantiatedMethod(new Instantiation(logicalReturnType)); - //} - //else - //{ - // if (isValueTask) - // { - // finalizeTaskReturningThunkMd = context.SystemModule - // .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) - // .GetKnownMethod("FinalizeValueTaskReturningThunk"u8, null); - // } - // else - // { - // finalizeTaskReturningThunkMd = context.SystemModule - // .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) - // .GetKnownMethod("FinalizeTaskReturningThunk"u8, null); - // } - //} - //codestream.Emit(ILOpcode.call, emitter.NewToken(finalizeTaskReturningThunkMd)); + MethodDesc finalizeTaskReturningThunkMd; + + if (isValueTask) + { + finalizeTaskReturningThunkMd = context.SystemModule + .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) + .GetKnownMethod("FinalizeValueTaskReturningThunk"u8, null); + } + else + { + finalizeTaskReturningThunkMd = context.SystemModule + .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) + .GetKnownMethod("FinalizeTaskReturningThunk"u8, null); + } + + if (logicalReturnType != null) + { + finalizeTaskReturningThunkMd = finalizeTaskReturningThunkMd.MakeInstantiatedMethod(new Instantiation(logicalReturnType)); + } + + codestream.Emit(ILOpcode.call, emitter.NewToken(finalizeTaskReturningThunkMd)); codestream.EmitStLoc(returnTaskLocal); codestream.Emit(ILOpcode.leave, returnTaskLabel); codestream.EndTry(tryFinallyRegion); } - // + { codestream.BeginHandler(tryFinallyRegion); - // TODO: Fix this (ExecutionAndSyncBlockStore is not available in Native AOT). - - // codestream.EmitLdLoca(executionAndSyncBlockStoreLocal); - // codestream.Emit(ILOpcode.call, emitter.NewToken(executionAndSyncBlockStoreType.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/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs index bfffd099ee60b3..c671df85517578 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs @@ -517,8 +517,15 @@ public class ILExceptionRegionBuilder internal ILCodeStream _endHandlerStream; internal int _endHandlerOffset; - internal ILExceptionRegionBuilder() + internal ILExceptionRegionKind _exceptionRegionKind; + internal TypeDesc _catchExceptionType; + + internal ILExceptionRegionBuilder(ILExceptionRegionKind exceptionRegionKind, TypeDesc catchExceptionType = null) { + _exceptionRegionKind = exceptionRegionKind; + _catchExceptionType = catchExceptionType; + Debug.Assert((exceptionRegionKind == ILExceptionRegionKind.Catch && catchExceptionType != null) + || (exceptionRegionKind != ILExceptionRegionKind.Catch && catchExceptionType == null)); } internal int TryOffset => _beginTryStream.RelativeToAbsoluteOffset(_beginTryOffset); @@ -669,8 +676,7 @@ public class ILEmitter private ArrayBuilder _codeStreams; private ArrayBuilder _locals; private ArrayBuilder _tokens; - private ArrayBuilder _catchRegions; - private ArrayBuilder _finallyRegions; + private ArrayBuilder _exceptionRegions; public ILEmitter() { @@ -729,17 +735,17 @@ public ILCodeLabel NewCodeLabel() } // For now, only catches exceptions of type Exception. - public ILExceptionRegionBuilder NewCatchRegion() + public ILExceptionRegionBuilder NewCatchRegion(TypeDesc exceptionType) { - var region = new ILExceptionRegionBuilder(); - _catchRegions.Add(region); + var region = new ILExceptionRegionBuilder(ILExceptionRegionKind.Catch, exceptionType); + _exceptionRegions.Add(region); return region; } public ILExceptionRegionBuilder NewFinallyRegion() { - var region = new ILExceptionRegionBuilder(); - _finallyRegions.Add(region); + var region = new ILExceptionRegionBuilder(ILExceptionRegionKind.Finally); + _exceptionRegions.Add(region); return region; } @@ -791,36 +797,34 @@ public MethodIL Link(MethodDesc owningMethod) ILExceptionRegion[] exceptionRegions = null; - int numberOfExceptionRegions = _catchRegions.Count + _finallyRegions.Count; + int numberOfExceptionRegions = _exceptionRegions.Count; if (numberOfExceptionRegions > 0) { exceptionRegions = new ILExceptionRegion[numberOfExceptionRegions]; - - TypeDesc exceptionType = owningMethod.Context.SystemModule.GetKnownType("System"u8, "Exception"u8); - - int exceptionTypeToken = (int)NewToken(exceptionType); - - for (int i = 0; i < _catchRegions.Count; i++) + for (int i = 0; i < _exceptionRegions.Count; i++) { - ILExceptionRegionBuilder region = _catchRegions[i]; + ILExceptionRegionBuilder region = _exceptionRegions[i]; Debug.Assert(region.IsDefined); - exceptionRegions[i] = new ILExceptionRegion(ILExceptionRegionKind.Catch, + int exceptionTypeToken = (region._catchExceptionType != null) ? (int)NewToken(region._catchExceptionType) : 0; + + exceptionRegions[i] = new ILExceptionRegion(region._exceptionRegionKind, region.TryOffset, region.TryLength, region.HandlerOffset, region.HandlerLength, classToken: exceptionTypeToken, filterOffset: 0); } - for (int i = 0; i < _finallyRegions.Count; i++) + // Sort exception regions so that innermost (most nested) regions come first + // as this is required by the spec. + // Innermost regions have higher TryOffset and smaller TryLength. + Array.Sort(exceptionRegions, (a, b) => { - ILExceptionRegionBuilder region = _finallyRegions[i]; + int offsetComparison = b.TryOffset.CompareTo(a.TryOffset); + if (offsetComparison != 0) + return offsetComparison; - Debug.Assert(region.IsDefined); - - exceptionRegions[_catchRegions.Count + i] = new ILExceptionRegion(ILExceptionRegionKind.Finally, - region.TryOffset, region.TryLength, region.HandlerOffset, region.HandlerLength, - classToken: 0, filterOffset: 0); - } + return a.TryLength.CompareTo(b.TryLength); + }); } var result = new ILStubMethodIL(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), exceptionRegions, debugInfo); diff --git a/src/coreclr/vm/asyncthunks.cpp b/src/coreclr/vm/asyncthunks.cpp index ed80604e0302f7..9fbca119ed1bff 100644 --- a/src/coreclr/vm/asyncthunks.cpp +++ b/src/coreclr/vm/asyncthunks.cpp @@ -133,7 +133,7 @@ void MethodDesc::EmitTaskReturningThunk(MethodDesc* pAsyncOtherVariant, MetaSig& } int token; - _ASSERTE(!pAsyncOtherVariant->IsWrapperStub()); // Would it be better to move the assertion to the top of this method? + _ASSERTE(!pAsyncOtherVariant->IsWrapperStub()); if (pAsyncOtherVariant->HasClassOrMethodInstantiation()) { // For generic code emit generic signatures. From 67c25f3ba3406df64fc1de521b9dd6893563baaf Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Tue, 11 Nov 2025 01:48:55 -0800 Subject: [PATCH 10/13] PR feedback --- .../src/System.Private.CoreLib.csproj | 1 - .../src/System/StubHelpers.NativeAot.cs | 10 ------ .../Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 34 +++++++++++-------- 3 files changed, 19 insertions(+), 26 deletions(-) delete mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/StubHelpers.NativeAot.cs diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index b5329c522da12c..01e53975c4819b 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -244,7 +244,6 @@ - diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/StubHelpers.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/StubHelpers.NativeAot.cs deleted file mode 100644 index a20f3186b4d27b..00000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/StubHelpers.NativeAot.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.StubHelpers -{ - internal static partial class StubHelpers - { - internal static object? AsyncCallContinuation() => throw new Exception(); // Unconditionally expanded intrinsic - } -} diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index a82e744119143c..220cd09c34e0e3 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -99,12 +99,11 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me } MethodDesc asyncCallContinuationMd = context.SystemModule - .GetKnownType("System.StubHelpers"u8, "StubHelpers"u8) + .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) .GetKnownMethod("AsyncCallContinuation"u8, null); codestream.Emit(ILOpcode.call, emitter.NewToken(asyncCallContinuationMd)); - codestream.Emit(ILOpcode.brfalse, finishedLabel); codestream.Emit(ILOpcode.leave, suspendedLabel); codestream.EmitLabel(finishedLabel); @@ -158,20 +157,25 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me { codestream.BeginHandler(tryCatchRegion); - MethodDesc fromExceptionMd; - if (isValueTask) - { - fromExceptionMd = context.SystemModule - .GetKnownType("System.Threading.Tasks"u8, "ValueTask"u8) - .GetKnownMethod("FromException"u8, null); - } - else - { - fromExceptionMd = context.SystemModule - .GetKnownType("System.Threading.Tasks"u8, "Task"u8) - .GetKnownMethod("FromException"u8, null); - } + TypeDesc exceptionType = context.GetWellKnownType(WellKnownType.Exception); + + // For generic methods (Task/ValueTask), the signature uses a method type parameter (!!0) + // For non-generic methods (Task/ValueTask), the signature uses the concrete return type + TypeDesc fromExceptionSignatureReturnType = logicalReturnType != null + ? ((MetadataType)returnType.GetTypeDefinition()).MakeInstantiatedType(context.GetSignatureVariable(0, true)) + : returnType; + + MethodSignature fromExceptionSignature = new MethodSignature( + MethodSignatureFlags.Static, + genericParameterCount: logicalReturnType != null ? 1 : 0, + returnType: fromExceptionSignatureReturnType, + parameters: new[] { exceptionType }); + + MethodDesc fromExceptionMd = context.SystemModule + .GetKnownType("System.Threading.Tasks"u8, isValueTask ? "ValueTask"u8 : "Task"u8) + .GetKnownMethod("FromException"u8, fromExceptionSignature); + // Instantiate the generic method if we have a generic return type (Task or ValueTask) if (logicalReturnType != null) { fromExceptionMd = fromExceptionMd.MakeInstantiatedMethod(new Instantiation(logicalReturnType)); From a86fbf73530ad66ebb86297f99833393cad79b84 Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Tue, 11 Nov 2025 01:52:26 -0800 Subject: [PATCH 11/13] Nit --- src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs index c671df85517578..10d15a976b614b 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs @@ -734,7 +734,6 @@ public ILCodeLabel NewCodeLabel() return newLabel; } - // For now, only catches exceptions of type Exception. public ILExceptionRegionBuilder NewCatchRegion(TypeDesc exceptionType) { var region = new ILExceptionRegionBuilder(ILExceptionRegionKind.Catch, exceptionType); From 49447467e369e32109495cdd2d137e7c749b1aec Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Tue, 11 Nov 2025 15:15:25 -0800 Subject: [PATCH 12/13] PR feedback --- .../Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index 220cd09c34e0e3..f485567734a1a0 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -71,13 +71,7 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me if (asyncMethod.OwningType.HasInstantiation) { - var inst = new TypeDesc[asyncMethod.OwningType.Instantiation.Length]; - for (int i = 0; i < inst.Length; i++) - { - inst[i] = context.GetSignatureVariable(i, false); - } - - var instantiatedType = context.GetInstantiatedType((MetadataType)asyncMethod.OwningType, new Instantiation(inst)); + var instantiatedType = (InstantiatedType)TypeSystemHelpers.InstantiateAsOpen(asyncMethod.OwningType); asyncMethod = context.GetMethodForInstantiatedType(asyncMethod, instantiatedType); } @@ -159,26 +153,31 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me TypeDesc exceptionType = context.GetWellKnownType(WellKnownType.Exception); - // For generic methods (Task/ValueTask), the signature uses a method type parameter (!!0) - // For non-generic methods (Task/ValueTask), the signature uses the concrete return type - TypeDesc fromExceptionSignatureReturnType = logicalReturnType != null - ? ((MetadataType)returnType.GetTypeDefinition()).MakeInstantiatedType(context.GetSignatureVariable(0, true)) - : returnType; - - MethodSignature fromExceptionSignature = new MethodSignature( - MethodSignatureFlags.Static, - genericParameterCount: logicalReturnType != null ? 1 : 0, - returnType: fromExceptionSignatureReturnType, - parameters: new[] { exceptionType }); - - MethodDesc fromExceptionMd = context.SystemModule - .GetKnownType("System.Threading.Tasks"u8, isValueTask ? "ValueTask"u8 : "Task"u8) - .GetKnownMethod("FromException"u8, fromExceptionSignature); - - // Instantiate the generic method if we have a generic return type (Task or ValueTask) + MethodDesc fromExceptionMd; if (logicalReturnType != null) { - fromExceptionMd = fromExceptionMd.MakeInstantiatedMethod(new Instantiation(logicalReturnType)); + MethodSignature fromExceptionSignature = new MethodSignature( + MethodSignatureFlags.Static, + genericParameterCount: 1, + returnType: ((MetadataType)returnType.GetTypeDefinition()).MakeInstantiatedType(context.GetSignatureVariable(0, true)), + parameters: new[] { exceptionType }); + + fromExceptionMd = context.SystemModule + .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) + .GetKnownMethod(isValueTask ? "ValueTaskFromException"u8 : "TaskFromException"u8, fromExceptionSignature) + .MakeInstantiatedMethod(new Instantiation(logicalReturnType)); + } + else + { + MethodSignature fromExceptionSignature = new MethodSignature( + MethodSignatureFlags.Static, + genericParameterCount: 0, + returnType: returnType, + parameters: new[] { exceptionType }); + + fromExceptionMd = context.SystemModule + .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) + .GetKnownMethod(isValueTask ? "ValueTaskFromException"u8 : "TaskFromException"u8, fromExceptionSignature); } codestream.Emit(ILOpcode.call, emitter.NewToken(fromExceptionMd)); From 869e6707e0e2852ea218c833c9fe9deb55664201 Mon Sep 17 00:00:00 2001 From: Eduardo Velarde Date: Wed, 12 Nov 2025 13:53:57 -0800 Subject: [PATCH 13/13] PR feedback --- .../Common/TypeSystem/IL/Stubs/AsyncThunks.cs | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs index f485567734a1a0..fd8d45455c7a72 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/AsyncThunks.cs @@ -37,9 +37,6 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me ILLocalVariable returnTaskLocal = emitter.NewLocal(returnType); - // TODO: Check if store/restore is responsibility of the async callee - // after https://github.com/dotnet/runtime/pull/121448 gets merged. - TypeDesc executionAndSyncBlockStoreType = context.SystemModule.GetKnownType("System.Runtime.CompilerServices"u8, "ExecutionAndSyncBlockStore"u8); ILLocalVariable executionAndSyncBlockStoreLocal = emitter.NewLocal(executionAndSyncBlockStoreType); @@ -110,7 +107,7 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me if (isValueTask) { fromResultMethod = context.SystemModule - .GetKnownType("System.Threading.Tasks"u8, "ValueTask`1"u8) + .GetKnownType("System.Threading.Tasks"u8, "ValueTask"u8) .GetKnownMethod("FromResult"u8, null) .MakeInstantiatedMethod(new Instantiation(logicalReturnType)); } @@ -160,7 +157,8 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me MethodSignatureFlags.Static, genericParameterCount: 1, returnType: ((MetadataType)returnType.GetTypeDefinition()).MakeInstantiatedType(context.GetSignatureVariable(0, true)), - parameters: new[] { exceptionType }); + parameters: new[] { exceptionType } + ); fromExceptionMd = context.SystemModule .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) @@ -173,7 +171,8 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me MethodSignatureFlags.Static, genericParameterCount: 0, returnType: returnType, - parameters: new[] { exceptionType }); + parameters: new[] { exceptionType } + ); fromExceptionMd = context.SystemModule .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) @@ -189,23 +188,32 @@ public static MethodIL EmitTaskReturningThunk(MethodDesc taskReturningMethod, Me codestream.EmitLabel(suspendedLabel); MethodDesc finalizeTaskReturningThunkMd; - - if (isValueTask) + if (logicalReturnType != null) { + MethodSignature finalizeReturningThunkSignature = new MethodSignature( + MethodSignatureFlags.Static, + genericParameterCount: 1, + returnType: ((MetadataType)returnType.GetTypeDefinition()).MakeInstantiatedType(context.GetSignatureVariable(0, true)), + parameters: Array.Empty() + ); + finalizeTaskReturningThunkMd = context.SystemModule .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) - .GetKnownMethod("FinalizeValueTaskReturningThunk"u8, null); + .GetKnownMethod(isValueTask ? "FinalizeValueTaskReturningThunk"u8 : "FinalizeTaskReturningThunk"u8, finalizeReturningThunkSignature) + .MakeInstantiatedMethod(new Instantiation(logicalReturnType)); } else { + MethodSignature finalizeReturningThunkSignature = new MethodSignature( + MethodSignatureFlags.Static, + genericParameterCount: 0, + returnType: returnType, + parameters: Array.Empty() + ); + finalizeTaskReturningThunkMd = context.SystemModule .GetKnownType("System.Runtime.CompilerServices"u8, "AsyncHelpers"u8) - .GetKnownMethod("FinalizeTaskReturningThunk"u8, null); - } - - if (logicalReturnType != null) - { - finalizeTaskReturningThunkMd = finalizeTaskReturningThunkMd.MakeInstantiatedMethod(new Instantiation(logicalReturnType)); + .GetKnownMethod(isValueTask ? "FinalizeValueTaskReturningThunk"u8 : "FinalizeTaskReturningThunk"u8, finalizeReturningThunkSignature); } codestream.Emit(ILOpcode.call, emitter.NewToken(finalizeTaskReturningThunkMd));