diff --git a/src/coreclr/jit/async.cpp b/src/coreclr/jit/async.cpp index 94f6b0e646675f..936d1c19976037 100644 --- a/src/coreclr/jit/async.cpp +++ b/src/coreclr/jit/async.cpp @@ -2871,6 +2871,16 @@ BasicBlock* AsyncTransformation::RethrowExceptionOnResumption(BasicBlock* GenTree* storeException = m_compiler->gtNewStoreLclVarNode(exceptionLclNum, exceptionInd); LIR::AsRange(resumeBB).InsertAtEnd(LIR::SeqTree(m_compiler, storeException)); + if (ReuseContinuations()) + { + // If we may reuse this continuation later then make sure we don't see the same exception again. + GenTree* continuation = m_compiler->gtNewLclvNode(m_compiler->lvaAsyncContinuationArg, TYP_REF); + unsigned exceptionOffset = OFFSETOF__CORINFO_Continuation__data + layout.ExceptionOffset; + GenTree* null = m_compiler->gtNewNull(); + GenTree* nullException = StoreAtOffset(continuation, exceptionOffset, null, TYP_REF); + LIR::AsRange(resumeBB).InsertAtEnd(LIR::SeqTree(m_compiler, nullException)); + } + GenTree* exception = m_compiler->gtNewLclVarNode(exceptionLclNum, TYP_REF); GenTree* null = m_compiler->gtNewNull(); GenTree* neNull = m_compiler->gtNewOperNode(GT_NE, TYP_INT, exception, null); @@ -3244,6 +3254,16 @@ void AsyncTransformation::CreateResumptionsAndSuspensions() // bool AsyncTransformation::ReuseContinuations() { +#ifdef DEBUG + static ConfigMethodRange s_range; + s_range.EnsureInit(JitConfig.JitAsyncReuseContinuationsRange()); + + if (!s_range.Contains(m_compiler->info.compMethodHash())) + { + return false; + } +#endif + return JitConfig.JitAsyncReuseContinuations() != 0; } diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index e5cfe83d7ac427..5f04e291d98af5 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -592,9 +592,11 @@ OPT_CONFIG_INTEGER(JitDoOptimizeMaskConversions, "JitDoOptimizeMaskConversions", OPT_CONFIG_INTEGER(JitOptimizeAwait, "JitOptimizeAwait", 1) // Perform optimization of Await intrinsics OPT_CONFIG_STRING(JitAsyncDefaultValueAnalysisRange, "JitAsyncDefaultValueAnalysisRange") // Enable async default value analysis based on method hash range +// Enable continuation reuse based on method hash range +OPT_CONFIG_STRING(JitAsyncReuseContinuationsRange, "JitAsyncReuseContinuationsRange") // Save and reuse continuation instances in runtime async functions. Also // implies use of shared continuation layouts for all suspension points. -RELEASE_CONFIG_INTEGER(JitAsyncReuseContinuations, "JitAsyncReuseContinuations", 0) +RELEASE_CONFIG_INTEGER(JitAsyncReuseContinuations, "JitAsyncReuseContinuations", 1) RELEASE_CONFIG_INTEGER(JitEnableOptRepeat, "JitEnableOptRepeat", 1) // If zero, do not allow JitOptRepeat RELEASE_CONFIG_METHODSET(JitOptRepeat, "JitOptRepeat") // Runs optimizer multiple times on specified methods diff --git a/src/tests/async/regression/125805.cs b/src/tests/async/regression/125805.cs new file mode 100644 index 00000000000000..3f2f0e043ed2c3 --- /dev/null +++ b/src/tests/async/regression/125805.cs @@ -0,0 +1,51 @@ +// 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 System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +public class Runtime_125805 +{ + [Fact] + public static void TestEntryPoint() + { + ExceptionReuse().GetAwaiter().GetResult(); + } + + private static async Task ExceptionReuse() + { + try + { + await Throws(); + Assert.Fail("Expected throw"); + } + catch (NullReferenceException) + { + } + + try + { + await NoThrow(); + } + catch (Exception ex) + { + Assert.Fail("Did not expect throw: " + ex); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static async Task Throws() + { + await Task.Yield(); + throw new NullReferenceException(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static async Task NoThrow() + { + await Task.Yield(); + } +} + diff --git a/src/tests/async/regression/125805.csproj b/src/tests/async/regression/125805.csproj new file mode 100644 index 00000000000000..3fc50cde4b3443 --- /dev/null +++ b/src/tests/async/regression/125805.csproj @@ -0,0 +1,5 @@ + + + + +