Uh oh!
There was an error while loading. Please reload this page.
Add RuntimeHelpers.IsRuntimeAsync intrinsic - #130899
Conversation
The interpreter and JIT fold this intrinsic to a constant based on whether the calling function is runtime async.
|
Azure Pipelines: Successfully started running 5 pipeline(s). 10 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
There was a problem hiding this comment.
Pull request overview
This PR introduces a new RuntimeHelpers.IsRuntimeAsync() intrinsic in System.Private.CoreLib, and wires it up so both the CoreCLR JIT and the CoreCLR interpreter fold it to a compile-time constant based on whether the current compilation is for an async-calling-convention method (runtime-async).
Changes:
- Add
RuntimeHelpers.IsRuntimeAsync()as an[Intrinsic]internal API stub in CoreLib. - Extend CoreCLR JIT named-intrinsic plumbing to recognize the method and expand it to
true/falseduring import based oncompIsAsync(). - Extend CoreCLR interpreter named-intrinsic plumbing to recognize and constant-fold the method based on
sig.isAsyncCall().
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs | Adds the new internal [Intrinsic] method stub IsRuntimeAsync(). |
| src/coreclr/jit/namedintrinsiclist.h | Adds a new NamedIntrinsic enum value for RuntimeHelpers.IsRuntimeAsync. |
| src/coreclr/jit/importercalls.cpp | Recognizes and expands the intrinsic during import to a constant using compIsAsync(). |
| src/coreclr/jit/fgbasic.cpp | Marks the intrinsic as foldable during IL stack simulation for jump target discovery. |
| src/coreclr/interpreter/intrinsics.cpp | Maps RuntimeHelpers.IsRuntimeAsync to the new NamedIntrinsic. |
| src/coreclr/interpreter/compiler.cpp | Expands the intrinsic to an ldc.i4 constant based on isAsyncCall(), and treats it as “must expand” for interpretation. |
jakobbotsch
commented
Jul 16, 2026
@EgorBot -intel -amd -arm --envvars DOTNET_JitDisasm:ReadLineAsync usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Text;usingSystem.Threading.Tasks;usingBenchmarkDotNet.Attributes;publicclassStreamReaderReadLineTests{privatestring_text;privatebyte[]_bytes;[ParamsSource(nameof(GetLineLengthRanges))]publicRangeLineLengthRange{get;set;}publicstaticIEnumerable<Range>GetLineLengthRanges(){yieldreturnnewRange(){Min=0,Max=0};yieldreturnnewRange(){Min=1,Max=1};yieldreturnnewRange(){Min=1,Max=8};yieldreturnnewRange(){Min=9,Max=32};yieldreturnnewRange(){Min=33,Max=128};yieldreturnnewRange(){Min=129,Max=1024};yieldreturnnewRange(){Min=1025,Max=2048};yieldreturnnewRange(){Min=0,Max=1024};}publicclassRange{publicintMin{get;set;}publicintMax{get;set;}publicoverridestringToString()=>$"[{Min,4}, {Max,4}]";}[GlobalSetup]publicvoidGlobalSetup(){_text=GenerateLinesText(LineLengthRange,16*1024);_bytes=Encoding.UTF8.GetBytes(_text);}[Benchmark]publicasyncTaskReadLineAsync(){using(StreamReaderreader=newStreamReader(newMemoryStream(_bytes))){while(awaitreader.ReadLineAsync()!=null);}}privatestaticstringGenerateLinesText(RangelineLengthRange,inttextTargetLength){intmin=lineLengthRange.Min;intmax=lineLengthRange.Max;stringnewLine=Environment.NewLine;varsb=newStringBuilder(textTargetLength+max+newLine.Length);varrandom=newRandom(42);while(sb.Length<textTargetLength){intcharsCount=random.Next(min,max);for(intc=0;c<charsCount;c++)sb.Append((char)random.Next('0','z'));sb.Append(newLine);}returnsb.ToString();}} |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
This reverts commit f27814f.
|
Azure Pipelines: Successfully started running 5 pipeline(s). 10 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
jakobbotsch
commented
Jul 16, 2026
Uh oh!
There was an error while loading. Please reload this page.
tannergooding
commented
Jul 16, 2026
Is this something we're going to consider making public longer term, or is it one of the internal-only APIs? -- Mostly wondering if I need to be tracking something for api-review, not asking for it to be or not. |
jakobbotsch
commented
Jul 16, 2026
I'm not sure yet. I think if everything was runtime async by default we would not need it. I think time will tell how often we end up needing this. |
Uh oh!
There was an error while loading. Please reload this page.
jakobbotsch
commented
Jul 17, 2026
/ba-g Timeouts |
The interpreter and JIT fold this intrinsic to a constant based on whether the calling function is runtime async.
The motivation is cases like #130872 and #130689 where there is a worry about potentially regressing async1 callers, especially for .NET 11 where runtime async is opt-in in Roslyn.