diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 8151dff192377a..632978641b9ee1 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -1160,6 +1160,7 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed // These are foldable if the first argument is a constant case NI_System_Type_get_IsValueType: + case NI_System_Type_get_IsByRefLike: case NI_System_Type_GetTypeFromHandle: case NI_System_String_get_Length: case NI_System_Buffers_Binary_BinaryPrimitives_ReverseEndianness: diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 54cedb357958ba..88be725e8b26ff 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -4282,14 +4282,16 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, } case NI_System_Type_get_IsValueType: + case NI_System_Type_get_IsByRefLike: { // Optimize // // call Type.GetTypeFromHandle (which is replaced with CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE) - // call Type.IsValueType + // call Type.IsXXX // // to `true` or `false` - // e.g. `typeof(int).IsValueType` => `true` + // e.g., `typeof(int).IsValueType` => `true` + // e.g., `typeof(Span).IsByRefLike` => `true` if (impStackTop().val->IsCall()) { GenTreeCall* call = impStackTop().val->AsCall(); @@ -4298,12 +4300,24 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, CORINFO_CLASS_HANDLE hClass = gtGetHelperArgClassHandle(call->gtCallArgs->GetNode()); if (hClass != NO_CLASS_HANDLE) { - retNode = - gtNewIconNode((eeIsValueClass(hClass) && - // pointers are not value types (e.g. typeof(int*).IsValueType is false) - info.compCompHnd->asCorInfoType(hClass) != CORINFO_TYPE_PTR) - ? 1 - : 0); + switch (ni) + { + case NI_System_Type_get_IsValueType: + retNode = gtNewIconNode( + (eeIsValueClass(hClass) && + // pointers are not value types (e.g. typeof(int*).IsValueType is false) + info.compCompHnd->asCorInfoType(hClass) != CORINFO_TYPE_PTR) + ? 1 + : 0); + break; + case NI_System_Type_get_IsByRefLike: + retNode = gtNewIconNode( + (info.compCompHnd->getClassAttribs(hClass) & CORINFO_FLG_BYREF_LIKE) ? 1 : 0); + break; + default: + NO_WAY("Intrinsic not supported in this path."); + } + impPopStack(); // drop CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE call } } @@ -5251,6 +5265,10 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) { result = NI_System_Type_get_IsValueType; } + else if (strcmp(methodName, "get_IsByRefLike") == 0) + { + result = NI_System_Type_get_IsByRefLike; + } else if (strcmp(methodName, "IsAssignableFrom") == 0) { result = NI_System_Type_IsAssignableFrom; diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 7f66f33e41d2e1..8d5a2f29b1c789 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -56,6 +56,7 @@ enum NamedIntrinsic : unsigned short NI_System_Threading_Thread_get_CurrentThread, NI_System_Threading_Thread_get_ManagedThreadId, NI_System_Type_get_IsValueType, + NI_System_Type_get_IsByRefLike, NI_System_Type_IsAssignableFrom, NI_System_Type_IsAssignableTo, NI_System_Type_op_Equality, diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index f92f977a0f1c6e..cf1b6e32f480a2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -51,7 +51,7 @@ protected Type() { } public virtual bool IsSZArray => throw NotImplemented.ByDesign; public virtual bool IsVariableBoundArray => IsArray && !IsSZArray; - public virtual bool IsByRefLike => throw new NotSupportedException(SR.NotSupported_SubclassOverride); + public virtual bool IsByRefLike { [Intrinsic] get => throw new NotSupportedException(SR.NotSupported_SubclassOverride); } public bool HasElementType => HasElementTypeImpl(); protected abstract bool HasElementTypeImpl(); @@ -110,10 +110,10 @@ public virtual Type[] GetGenericParameterConstraints() public bool IsPrimitive => IsPrimitiveImpl(); protected abstract bool IsPrimitiveImpl(); public bool IsValueType { [Intrinsic] get => IsValueTypeImpl(); } + protected virtual bool IsValueTypeImpl() => IsSubclassOf(typeof(ValueType)); [Intrinsic] public bool IsAssignableTo([NotNullWhen(true)] Type? targetType) => targetType?.IsAssignableFrom(this) ?? false; - protected virtual bool IsValueTypeImpl() => IsSubclassOf(typeof(ValueType)); public virtual bool IsSignatureType => false;