Skip to content

Commit 1e0c243

Browse files
Convert RuntimeHelpers.IsReferenceOrContainsReferences to JIT intrinsic (#103010)
* Convert IsReferenceOrContainsReferences to JIT intrinsic Collapse all to a single definition across the runtimes.
1 parent 8f2ca60 commit 1e0c243

File tree

16 files changed

+101
-105
lines changed

16 files changed

+101
-105
lines changed

src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -221,16 +221,6 @@ public static object GetUninitializedObject(
221221
[LibraryImport(QCall, EntryPoint = "ObjectNative_AllocateUninitializedClone")]
222222
internal static partial void AllocateUninitializedClone(ObjectHandleOnStack objHandle);
223223

224-
/// <returns>true if given type is reference type or value type that contains references</returns>
225-
[Intrinsic]
226-
public static bool IsReferenceOrContainsReferences<T>()
227-
// where T : allows ref struct // TODO https://github.com/dotnet/runtime/issues/102847
228-
{
229-
// The body of this function will be replaced by the EE with unsafe code!!!
230-
// See getILIntrinsicImplementationForRuntimeHelpers for how this happens.
231-
throw new InvalidOperationException();
232-
}
233-
234224
/// <returns>true if given type is bitwise equatable (memcmp can be used for equality checking)</returns>
235225
/// <remarks>
236226
/// Only use the result of this for Equals() comparison, not for CompareTo() comparison.

src/coreclr/jit/importercalls.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3362,6 +3362,19 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
33623362
break;
33633363
}
33643364

3365+
case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences:
3366+
{
3367+
assert(sig->sigInst.methInstCount == 1);
3368+
3369+
CORINFO_CLASS_HANDLE fromTypeHnd = sig->sigInst.methInst[0];
3370+
ClassLayout* fromLayout = nullptr;
3371+
var_types fromType = TypeHandleToVarType(fromTypeHnd, &fromLayout);
3372+
3373+
bool refOrContains = varTypeIsGC(fromType) || (fromLayout != nullptr && fromLayout->HasGCPtr());
3374+
retNode = refOrContains ? gtNewIconNode(1) : gtNewIconNode(0);
3375+
break;
3376+
}
3377+
33653378
case NI_System_Runtime_InteropService_MemoryMarshal_GetArrayDataReference:
33663379
{
33673380
assert(sig->numArgs == 1);
@@ -10103,6 +10116,11 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
1010310116
{
1010410117
result = NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant;
1010510118
}
10119+
else if (strcmp(methodName, "IsReferenceOrContainsReferences") == 0)
10120+
{
10121+
result =
10122+
NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences;
10123+
}
1010610124
}
1010710125
else if (strcmp(className, "Unsafe") == 0)
1010810126
{

src/coreclr/jit/namedintrinsiclist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ enum NamedIntrinsic : unsigned short
109109
NI_System_Runtime_CompilerServices_RuntimeHelpers_CreateSpan,
110110
NI_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray,
111111
NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant,
112+
NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences,
112113

113114
NI_System_Runtime_InteropService_MemoryMarshal_GetArrayDataReference,
114115

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.NativeAot.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,6 @@ public static unsafe bool TryEnsureSufficientExecutionStack()
181181
return (t_sufficientStackLimit = limit);
182182
}
183183

184-
[Intrinsic]
185-
public static unsafe bool IsReferenceOrContainsReferences<T>()
186-
{
187-
MethodTable* pEEType = MethodTable.Of<T>();
188-
return !pEEType->IsValueType || pEEType->ContainsGCPointers;
189-
}
190-
191184
[Intrinsic]
192185
internal static unsafe bool IsReference<T>()
193186
{

src/coreclr/tools/Common/TypeSystem/IL/Stubs/RuntimeHelpersIntrinsics.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,7 @@ public static MethodIL EmitIL(MethodDesc method)
4343
return null;
4444

4545
bool result;
46-
if (methodName == "IsReferenceOrContainsReferences")
47-
{
48-
result = elementType.IsGCPointer || (elementType is DefType defType && defType.ContainsGCPointers);
49-
}
50-
else if (methodName == "IsReference")
46+
if (methodName == "IsReference")
5147
{
5248
result = elementType.IsGCPointer;
5349
}

src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,16 @@ private void ImportCall(ILOpcode opcode, int token)
386386
}
387387
return;
388388
}
389+
390+
if (IsRuntimeHelpersIsReferenceOrContainsReferences(method))
391+
{
392+
return;
393+
}
394+
395+
if (IsMemoryMarshalGetArrayDataReference(method))
396+
{
397+
return;
398+
}
389399
}
390400

391401
TypeDesc exactType = method.OwningType;
@@ -1391,6 +1401,34 @@ private static bool IsEETypePtrOf(MethodDesc method)
13911401
return false;
13921402
}
13931403

1404+
private static bool IsRuntimeHelpersIsReferenceOrContainsReferences(MethodDesc method)
1405+
{
1406+
if (method.IsIntrinsic && method.Name == "IsReferenceOrContainsReferences" && method.Instantiation.Length == 1)
1407+
{
1408+
MetadataType owningType = method.OwningType as MetadataType;
1409+
if (owningType != null)
1410+
{
1411+
return owningType.Name == "RuntimeHelpers" && owningType.Namespace == "System.Runtime.CompilerServices";
1412+
}
1413+
}
1414+
1415+
return false;
1416+
}
1417+
1418+
private static bool IsMemoryMarshalGetArrayDataReference(MethodDesc method)
1419+
{
1420+
if (method.IsIntrinsic && method.Name == "GetArrayDataReference" && method.Instantiation.Length == 1)
1421+
{
1422+
MetadataType owningType = method.OwningType as MetadataType;
1423+
if (owningType != null)
1424+
{
1425+
return owningType.Name == "MemoryMarshal" && owningType.Namespace == "System.Runtime.InteropServices";
1426+
}
1427+
}
1428+
1429+
return false;
1430+
}
1431+
13941432
private DefType GetWellKnownType(WellKnownType wellKnownType)
13951433
{
13961434
return _compilation.TypeSystemContext.GetWellKnownType(wellKnownType);

src/coreclr/vm/corelib.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,6 @@ DEFINE_CLASS(RTFIELD, Reflection, RtFieldInfo)
632632
DEFINE_METHOD(RTFIELD, GET_FIELDHANDLE, GetFieldHandle, IM_RetIntPtr)
633633

634634
DEFINE_CLASS(RUNTIME_HELPERS, CompilerServices, RuntimeHelpers)
635-
DEFINE_METHOD(RUNTIME_HELPERS, IS_REFERENCE_OR_CONTAINS_REFERENCES, IsReferenceOrContainsReferences, NoSig)
636635
DEFINE_METHOD(RUNTIME_HELPERS, IS_BITWISE_EQUATABLE, IsBitwiseEquatable, NoSig)
637636
DEFINE_METHOD(RUNTIME_HELPERS, GET_METHOD_TABLE, GetMethodTable, NoSig)
638637
DEFINE_METHOD(RUNTIME_HELPERS, GET_RAW_DATA, GetRawData, NoSig)

src/coreclr/vm/jitinterface.cpp

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7381,34 +7381,6 @@ bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn,
73817381

73827382
mdMethodDef tk = ftn->GetMemberDef();
73837383

7384-
if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_REFERENCE_OR_CONTAINS_REFERENCES)->GetMemberDef())
7385-
{
7386-
_ASSERTE(ftn->HasMethodInstantiation());
7387-
Instantiation inst = ftn->GetMethodInstantiation();
7388-
7389-
_ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7390-
TypeHandle typeHandle = inst[0];
7391-
MethodTable * methodTable = typeHandle.GetMethodTable();
7392-
7393-
static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7394-
static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7395-
7396-
if (!methodTable->IsValueType() || methodTable->ContainsPointers())
7397-
{
7398-
methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7399-
}
7400-
else
7401-
{
7402-
methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7403-
}
7404-
7405-
methInfo->ILCodeSize = sizeof(returnTrue);
7406-
methInfo->maxStack = 1;
7407-
methInfo->EHcount = 0;
7408-
methInfo->options = (CorInfoOptions)0;
7409-
return true;
7410-
}
7411-
74127384
if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_BITWISE_EQUATABLE)->GetMemberDef())
74137385
{
74147386
_ASSERTE(ftn->HasMethodInstantiation());
@@ -14411,7 +14383,7 @@ HRESULT CEEInfo::getPgoInstrumentationResults(
1441114383
PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes)
1441214384
uint32_t * pCountSchemaItems, // pointer to the count schema items
1441314385
uint8_t ** pInstrumentationData, // pointer to the actual instrumentation data (pointer will not remain valid after jit completes)
14414-
PgoSource * pPgoSource,
14386+
PgoSource * pPgoSource,
1441514387
bool * pDynamicPgo
1441614388
)
1441714389
{

src/coreclr/vm/methodtable.h

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,11 +1551,10 @@ class MethodTable
15511551

15521552
inline WORD GetNumIntroducedInstanceFields();
15531553

1554-
// Note: This flag MUST be available even from an unrestored MethodTable - see GcScanRoots in siginfo.cpp.
1555-
DWORD ContainsPointers()
1554+
BOOL ContainsPointers()
15561555
{
15571556
LIMITED_METHOD_CONTRACT;
1558-
return GetFlag(enum_flag_ContainsPointers);
1557+
return !!GetFlag(enum_flag_ContainsPointers);
15591558
}
15601559

15611560
BOOL Collectible()
@@ -3375,32 +3374,24 @@ public :
33753374

33763375
enum_flag_Category_ElementTypeMask = 0x000E0000, // bits that matter for element type mask
33773376

3378-
3379-
// GC depends on this bit
3380-
enum_flag_HasFinalizer = 0x00100000, // instances require finalization
3381-
3382-
enum_flag_IDynamicInterfaceCastable = 0x10000000, // class implements IDynamicInterfaceCastable interface
3383-
3377+
enum_flag_HasFinalizer = 0x00100000, // instances require finalization. GC depends on this bit.
3378+
enum_flag_Collectible = 0x00200000, // GC depends on this bit.
33843379
enum_flag_ICastable = 0x00400000, // class implements ICastable interface
33853380

33863381
#ifdef FEATURE_64BIT_ALIGNMENT
33873382
enum_flag_RequiresAlign8 = 0x00800000, // Type requires 8-byte alignment (only set on platforms that require this and don't get it implicitly)
33883383
#endif
33893384

3390-
enum_flag_ContainsPointers = 0x01000000,
3391-
3385+
enum_flag_ContainsPointers = 0x01000000, // Contains object references
33923386
enum_flag_HasTypeEquivalence = 0x02000000, // can be equivalent to another type
3387+
enum_flag_IsTrackedReferenceWithFinalizer = 0x04000000,
3388+
// unused = 0x08000000,
33933389

3394-
enum_flag_IsTrackedReferenceWithFinalizer = 0x04000000,
3395-
3396-
// GC depends on this bit
3397-
enum_flag_Collectible = 0x00200000,
3398-
enum_flag_ContainsGenericVariables = 0x20000000, // we cache this flag to help detect these efficiently and
3399-
// to detect this condition when restoring
3400-
3390+
enum_flag_IDynamicInterfaceCastable = 0x10000000, // class implements IDynamicInterfaceCastable interface
3391+
enum_flag_ContainsGenericVariables = 0x20000000, // we cache this flag to help detect these efficiently and
3392+
// to detect this condition when restoring
34013393
enum_flag_ComObject = 0x40000000, // class is a com object
3402-
3403-
enum_flag_HasComponentSize = 0x80000000, // This is set if component size is used for flags.
3394+
enum_flag_HasComponentSize = 0x80000000, // This is set if component size is used for flags.
34043395

34053396
// Types that require non-trivial interface cast have this bit set in the category
34063397
enum_flag_NonTrivialInterfaceCast = enum_flag_Category_Array

src/coreclr/vm/methodtablebuilder.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3858,7 +3858,7 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
38583858

38593859
FieldDesc * pFD;
38603860
DWORD dwLog2FieldSize = 0;
3861-
BOOL bCurrentFieldIsGCPointer = FALSE;
3861+
BOOL bCurrentFieldIsObjectRef = FALSE;
38623862
mdToken dwByValueClassToken = 0;
38633863
MethodTable * pByValueClass = NULL;
38643864
BOOL fIsByValue = FALSE;
@@ -4030,7 +4030,7 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
40304030
case ELEMENT_TYPE_OBJECT:
40314031
{
40324032
dwLog2FieldSize = LOG2_PTRSIZE;
4033-
bCurrentFieldIsGCPointer = TRUE;
4033+
bCurrentFieldIsObjectRef = TRUE;
40344034
FieldDescElementType = ELEMENT_TYPE_CLASS;
40354035

40364036
if (!fIsStatic)
@@ -4375,7 +4375,7 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
43754375
IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_placement.m_offset));
43764376
else if (IsManagedSequential() && !fIsStatic)
43774377
IfFailThrow(pFD->SetOffset(pLayoutFieldInfo->m_placement.m_offset));
4378-
else if (bCurrentFieldIsGCPointer)
4378+
else if (bCurrentFieldIsObjectRef)
43794379
pFD->SetOffset(FIELD_OFFSET_UNPLACED_GC_PTR);
43804380
else
43814381
pFD->SetOffset(FIELD_OFFSET_UNPLACED);
@@ -4391,7 +4391,7 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
43914391

43924392
dwCurrentDeclaredField++;
43934393

4394-
if (bCurrentFieldIsGCPointer)
4394+
if (bCurrentFieldIsObjectRef)
43954395
{
43964396
bmtFP->NumInstanceGCPointerFields++;
43974397
}
@@ -4469,7 +4469,7 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
44694469
{
44704470
bmtFP->NumThreadStaticFieldsOfSize[dwLog2FieldSize]++;
44714471

4472-
if (bCurrentFieldIsGCPointer)
4472+
if (bCurrentFieldIsObjectRef)
44734473
bmtFP->NumThreadStaticGCPointerFields++;
44744474

44754475
if (fIsByValue)
@@ -4479,7 +4479,7 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
44794479
{
44804480
bmtFP->NumRegularStaticFieldsOfSize[dwLog2FieldSize]++;
44814481

4482-
if (bCurrentFieldIsGCPointer)
4482+
if (bCurrentFieldIsObjectRef)
44834483
bmtFP->NumRegularStaticGCPointerFields++;
44844484

44854485
if (fIsByValue)

0 commit comments

Comments
 (0)