Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3583,8 +3583,11 @@ void Compiler::fgFindBasicBlocks()
}

// Use a spill temp for the return value if there are multiple return blocks,
// or if the inlinee has GC ref locals.
if ((info.compRetNativeType != TYP_VOID) && ((fgReturnCount > 1) || impInlineInfo->HasGcRefLocals()))
// if the inlinee has GC ref locals, or if async contexts need save/restore.
// In the latter cases we will need to insert IR after the return.
if ((info.compRetNativeType != TYP_VOID) &&
((fgReturnCount > 1) || impInlineInfo->HasGcRefLocals() ||
((info.compMethodInfo->options & CORINFO_ASYNC_SAVE_CONTEXTS) != 0)))
{
// If we've spilled the ret expr to a temp we can reuse the temp
// as the inlinee return spill temp.
Expand Down
4 changes: 1 addition & 3 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11254,8 +11254,7 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode)

if (fgNeedReturnSpillTemp())
{
assert(info.compRetNativeType != TYP_VOID &&
(fgMoreThanOneReturnBlock() || impInlineInfo->HasGcRefLocals()));
assert(info.compRetNativeType != TYP_VOID);

// If this method returns a ref type, track the actual types seen in the returns.
if (info.compRetType == TYP_REF)
Expand Down Expand Up @@ -11331,7 +11330,6 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode)
// in this case we have to insert multiple struct copies to the temp
// and the retexpr is just the temp.
assert(info.compRetNativeType != TYP_VOID);
assert(fgMoreThanOneReturnBlock() || impInlineInfo->HasGcRefLocals());
Comment thread
jakobbotsch marked this conversation as resolved.

impStoreToTemp(lvaInlineeReturnSpillTemp, op2, CHECK_SPILL_ALL);
}
Expand Down
55 changes: 55 additions & 0 deletions src/tests/async/regression/125042.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// Generated by Fuzzlyn v3.3 on 2026-03-01 17:28:06
// Run on Arm64 Linux
// Seed: 17604030292119785473-async,runtimeasync,vectort,vector64,vector128,armadvsimd,armadvsimdarm64,armaes,armarmbase,armarmbasearm64,armcrc32,armcrc32arm64,armdp,armrdm,armrdmarm64,armsha1,armsha256,armsve,armsve2
// Reduced from 44.5 KiB to 0.8 KiB in 00:00:29
// Release: Runs successfully
// Release with Runtime Async: Throws 'System.InvalidOperationException'

using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

// When an async method that modifies an AsyncLocal is inlined with runtime async,
// the "Save contexts around async calls" phase wraps the body in a try/fault that
// restores the execution context on exit. The return value expression
// (GetAsyncLocal1) must be evaluated inside the try block before the context is
// restored; otherwise the AsyncLocal read sees a null value and throws.

public class Runtime_125042
{
public static AsyncLocal<bool?> s_asyncLocal1 = new AsyncLocal<bool?>();

[MethodImpl(MethodImplOptions.NoInlining)]
public static bool GetAsyncLocal1()
{
return s_asyncLocal1.Value.Value;
}

[Fact]
public static void TestEntryPoint()
{
M0().GetAwaiter().GetResult();
}

private static async Task M0()
{
var vr3 = (sbyte)0;
var vr2 = Vector128.CreateScalar(vr3);
var vr1 = await M1(true, vr2);
var vr5 = (sbyte)-1;
var vr4 = Vector128.CreateScalar(vr5);
bool vr0 = await M1(vr1, vr4);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static async Task<bool> M1(bool arg1, Vector128<sbyte> arg2)
{
s_asyncLocal1.Value = arg1;
return GetAsyncLocal1();
}
}
5 changes: 5 additions & 0 deletions src/tests/async/regression/125042.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk.IL">
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>
Loading