diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index b8dd968dfa0f82..dcc0cbf7e0a6b7 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -4032,6 +4032,19 @@ bool InterpCompiler::EmitNamedIntrinsicCall(NamedIntrinsic ni, bool nonVirtualCa return true; } + case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsRuntimeAsync: + { + int32_t result = m_methodInfo->args.isAsyncCall() ? 1 : 0; + + AddIns(INTOP_LDC_I4); + m_pLastNewIns->data[0] = result; + + PushInterpType(InterpTypeI4, nullptr); + m_pLastNewIns->SetDVar(m_pStackPointer[-1].var); + + return true; + } + case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences: { CORINFO_CLASS_HANDLE clsHnd = sig.sigInst.methInst[0]; @@ -5140,6 +5153,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re ni == NI_System_StubHelpers_NextCallReturnAddress || ni == NI_System_Runtime_CompilerServices_RuntimeHelpers_SetNextCallGenericContext || ni == NI_System_Runtime_CompilerServices_RuntimeHelpers_SetNextCallAsyncContinuation || + ni == NI_System_Runtime_CompilerServices_RuntimeHelpers_IsRuntimeAsync || ni == NI_System_Runtime_CompilerServices_AsyncHelpers_AsyncCallContinuation || ni == NI_System_Runtime_CompilerServices_AsyncHelpers_AsyncSuspend || ni == NI_System_Runtime_CompilerServices_AsyncHelpers_TailAwait); diff --git a/src/coreclr/interpreter/intrinsics.cpp b/src/coreclr/interpreter/intrinsics.cpp index 38e31e24a1cf08..3b8af0065d67ed 100644 --- a/src/coreclr/interpreter/intrinsics.cpp +++ b/src/coreclr/interpreter/intrinsics.cpp @@ -108,6 +108,8 @@ NamedIntrinsic GetNamedIntrinsic(COMP_HANDLE compHnd, CORINFO_METHOD_HANDLE comp { if (!strcmp(methodName, "IsReferenceOrContainsReferences")) return NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences; + else if (!strcmp(methodName, "IsRuntimeAsync")) + return NI_System_Runtime_CompilerServices_RuntimeHelpers_IsRuntimeAsync; else if (!strcmp(methodName, "GetMethodTable")) return NI_System_Runtime_CompilerServices_RuntimeHelpers_GetMethodTable; else if (!strcmp(methodName, "SetNextCallGenericContext")) diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 71d25be333fcfd..875bd4d41c1c2f 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -1170,6 +1170,12 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed foldableIntrinsic = true; break; + case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsRuntimeAsync: + // RuntimeHelpers.IsRuntimeAsync is always folded into a const + pushedStack.PushConstant(); + foldableIntrinsic = true; + break; + // These are foldable if the first argument is a constant case NI_PRIMITIVE_LeadingZeroCount: case NI_PRIMITIVE_Log2: diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index b1322a05ef7c76..721d65b68f3aa3 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -3508,6 +3508,12 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, return gtNewNothingNode(); } + if (ni == NI_System_Runtime_CompilerServices_RuntimeHelpers_IsRuntimeAsync) + { + JITDUMP("\nExpanding RuntimeHelpers.IsRuntimeAsync to %s early\n", compIsAsync() ? "true" : "false"); + return compIsAsync() ? gtNewTrue() : gtNewFalse(); + } + bool betterToExpand = false; // Allow some lightweight intrinsics in Tier0 which can improve throughput @@ -11429,6 +11435,10 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) { result = NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant; } + else if (strcmp(methodName, "IsRuntimeAsync") == 0) + { + result = NI_System_Runtime_CompilerServices_RuntimeHelpers_IsRuntimeAsync; + } else if (strcmp(methodName, "WriteBarrier") == 0) { result = NI_System_Runtime_CompilerServices_RuntimeHelpers_WriteBarrier; diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index edfb638bd1e5fb..a78298820e8dbe 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -124,6 +124,7 @@ enum NamedIntrinsic : unsigned short NI_System_Runtime_CompilerServices_RuntimeHelpers_CreateSpan, NI_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray, NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant, + NI_System_Runtime_CompilerServices_RuntimeHelpers_IsRuntimeAsync, NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences, NI_System_Runtime_CompilerServices_RuntimeHelpers_GetMethodTable, NI_System_Runtime_CompilerServices_RuntimeHelpers_WriteBarrier, diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index f9f228e6aea688..038452a1c8faf3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -179,6 +179,11 @@ public static ReadOnlySpan CreateSpan(RuntimeFieldHandle fldHandle) internal static bool IsKnownConstant(T t) where T : struct => false; #pragma warning restore IDE0060 + // Returns true if the method being compiled is a runtime-async method. + // This is folded to a compile-time constant by the JIT and the interpreter. + [Intrinsic] + internal static bool IsRuntimeAsync() => false; + /// true if the given type is a reference type or a value type that contains references or by-refs; otherwise, false. [Intrinsic] public static bool IsReferenceOrContainsReferences() where T : allows ref struct => IsReferenceOrContainsReferences();