Skip to content

Commit

Permalink
Add RuntimeHelpers.IsReferenceOrContainsReferences<T>() (dotnet#9541)
Browse files Browse the repository at this point in the history
Rename JitHelpers.ContainsReferences<T>() to RuntimeHelpers.IsReferenceOrContainsReferences<T>() and make it public.

Work towards https://github.com/dotnet/corefx/issues/14047
  • Loading branch information
jkotas authored and jorive committed May 4, 2017
1 parent 8d1b370 commit 3f98990
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 55 deletions.
21 changes: 11 additions & 10 deletions src/mscorlib/src/System/Collections/Generic/List.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
**
**
===========================================================*/

using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;

namespace System.Collections.Generic
{
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Collections.ObjectModel;
using Runtime.CompilerServices;

// Implements a variable-size List that uses an array of objects to store the
// elements. A List has a capacity, which is the allocated length
// of the internal array. As elements are added to a List, the capacity
Expand Down Expand Up @@ -292,7 +293,7 @@ public int BinarySearch(T item, IComparer<T> comparer)
// Clears the contents of List.
public void Clear()
{
if (JitHelpers.ContainsReferences<T>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
int size = _size;
_size = 0;
Expand Down Expand Up @@ -863,7 +864,7 @@ public int RemoveAll(Predicate<T> match) {
}
}

if (JitHelpers.ContainsReferences<T>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
Array.Clear(_items, freeIndex, _size - freeIndex); // Clear the elements so that the gc can reclaim the references.
}
Expand All @@ -887,7 +888,7 @@ public void RemoveAt(int index) {
{
Array.Copy(_items, index + 1, _items, index, _size - index);
}
if (JitHelpers.ContainsReferences<T>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
_items[_size] = default(T);
}
Expand Down Expand Up @@ -917,7 +918,7 @@ public void RemoveRange(int index, int count) {
}

_version++;
if (JitHelpers.ContainsReferences<T>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
Array.Clear(_items, _size, count);
}
Expand Down
2 changes: 1 addition & 1 deletion src/mscorlib/src/System/ReadOnlySpan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public ReadOnlySpan(T[] array, int start, int length)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe ReadOnlySpan(void* pointer, int length)
{
if (JitHelpers.ContainsReferences<T>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
if (length < 0)
ThrowHelper.ThrowArgumentOutOfRangeException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ internal static void ExecuteBackoutCodeHelper(Object backoutCode, Object userDat
{
((CleanupCode)backoutCode)(userData, exceptionThrown);
}

/// <returns>true if given type is reference type or value type that contains references</returns>
static public bool IsReferenceOrContainsReferences<T>()
{
// The body of this function will be replaced by the EE with unsafe code!!!
// See getILIntrinsicImplementation for how this happens.
throw new InvalidOperationException();
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -223,14 +223,6 @@ static internal bool ByRefLessThan<T>(ref T refA, ref T refB)
throw new InvalidOperationException();
}

/// <returns>true if given type is reference type or value type that contains references</returns>
static internal bool ContainsReferences<T>()
{
// The body of this function will be replaced by the EE with unsafe code!!!
// See getILIntrinsicImplementation for how this happens.
throw new InvalidOperationException();
}

static internal ref T GetArrayData<T>(T[] array)
{
// The body of this function will be replaced by the EE with unsafe code!!!
Expand Down
16 changes: 8 additions & 8 deletions src/mscorlib/src/System/Span.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public Span(T[] array, int start, int length)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe Span(void* pointer, int length)
{
if (JitHelpers.ContainsReferences<T>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
if (length < 0)
ThrowHelper.ThrowArgumentOutOfRangeException();
Expand Down Expand Up @@ -451,7 +451,7 @@ public static class Span
public static Span<byte> AsBytes<T>(this Span<T> source)
where T : struct
{
if (JitHelpers.ContainsReferences<T>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));

return new Span<byte>(
Expand All @@ -470,7 +470,7 @@ ref Unsafe.As<T, byte>(ref source.DangerousGetPinnableReference()),
public static ReadOnlySpan<byte> AsBytes<T>(this ReadOnlySpan<T> source)
where T : struct
{
if (JitHelpers.ContainsReferences<T>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));

return new ReadOnlySpan<byte>(
Expand All @@ -493,9 +493,9 @@ public static Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source)
where TFrom : struct
where TTo : struct
{
if (JitHelpers.ContainsReferences<TFrom>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
if (JitHelpers.ContainsReferences<TTo>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));

return new Span<TTo>(
Expand All @@ -518,9 +518,9 @@ public static ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TF
where TFrom : struct
where TTo : struct
{
if (JitHelpers.ContainsReferences<TFrom>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
if (JitHelpers.ContainsReferences<TTo>())
if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));

return new ReadOnlySpan<TTo>(
Expand Down Expand Up @@ -597,7 +597,7 @@ internal static unsafe void CopyTo<T>(ref T destination, ref T source, int eleme
if (Unsafe.AreSame(ref destination, ref source))
return;

if (!JitHelpers.ContainsReferences<T>())
if (!RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
fixed (byte* pDestination = &Unsafe.As<T, byte>(ref destination))
{
Expand Down
72 changes: 45 additions & 27 deletions src/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6992,33 +6992,6 @@ bool getILIntrinsicImplementation(MethodDesc * ftn,
methInfo->options = (CorInfoOptions)0;
return true;
}
else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__CONTAINSREFERENCES)->GetMemberDef())
{
_ASSERTE(ftn->HasMethodInstantiation());
Instantiation inst = ftn->GetMethodInstantiation();

_ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
TypeHandle typeHandle = inst[0];
MethodTable * methodTable = typeHandle.GetMethodTable();

static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };

if (!methodTable->IsValueType() || methodTable->ContainsPointers())
{
methInfo->ILCode = const_cast<BYTE*>(returnTrue);
}
else
{
methInfo->ILCode = const_cast<BYTE*>(returnFalse);
}

methInfo->ILCodeSize = sizeof(returnTrue);
methInfo->maxStack = 1;
methInfo->EHcount = 0;
methInfo->options = (CorInfoOptions)0;
return true;
}
#endif // FEATURE_SPAN_OF_T

return false;
Expand Down Expand Up @@ -7272,6 +7245,47 @@ bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn,
return true;
}

bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn,
CORINFO_METHOD_INFO * methInfo)
{
STANDARD_VM_CONTRACT;

// Precondition: ftn is a method in mscorlib
_ASSERTE(ftn->GetModule()->IsSystem());

mdMethodDef tk = ftn->GetMemberDef();

if (tk == MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_REFERENCE_OR_CONTAINS_REFERENCES)->GetMemberDef())
{
_ASSERTE(ftn->HasMethodInstantiation());
Instantiation inst = ftn->GetMethodInstantiation();

_ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
TypeHandle typeHandle = inst[0];
MethodTable * methodTable = typeHandle.GetMethodTable();

static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };

if (!methodTable->IsValueType() || methodTable->ContainsPointers())
{
methInfo->ILCode = const_cast<BYTE*>(returnTrue);
}
else
{
methInfo->ILCode = const_cast<BYTE*>(returnFalse);
}

methInfo->ILCodeSize = sizeof(returnTrue);
methInfo->maxStack = 1;
methInfo->EHcount = 0;
methInfo->options = (CorInfoOptions)0;
return true;
}

return false;
}

//---------------------------------------------------------------------------------------
//
//static
Expand Down Expand Up @@ -7323,6 +7337,10 @@ getMethodInfoHelper(
{
fILIntrinsic = getILIntrinsicImplementationForVolatile(ftn, methInfo);
}
else if (MscorlibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS))
{
fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo);
}

if (!fILIntrinsic)
{
Expand Down
2 changes: 1 addition & 1 deletion src/vm/mscorlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,7 @@ DEFINE_CLASS(RUNTIME_HELPERS, CompilerServices, RuntimeHelpers)
DEFINE_METHOD(RUNTIME_HELPERS, PREPARE_CONSTRAINED_REGIONS, PrepareConstrainedRegions, SM_RetVoid)
DEFINE_METHOD(RUNTIME_HELPERS, PREPARE_CONSTRAINED_REGIONS_NOOP, PrepareConstrainedRegionsNoOP, SM_RetVoid)
DEFINE_METHOD(RUNTIME_HELPERS, EXECUTE_BACKOUT_CODE_HELPER, ExecuteBackoutCodeHelper, SM_Obj_Obj_Bool_RetVoid)
DEFINE_METHOD(RUNTIME_HELPERS, IS_REFERENCE_OR_CONTAINS_REFERENCES, IsReferenceOrContainsReferences, NoSig)

DEFINE_CLASS(JIT_HELPERS, CompilerServices, JitHelpers)
#ifdef _DEBUG
Expand All @@ -1195,7 +1196,6 @@ DEFINE_METHOD(JIT_HELPERS, UNSAFE_CAST_TO_STACKPTR,UnsafeCastToStackPoi
#ifdef FEATURE_SPAN_OF_T
DEFINE_METHOD(JIT_HELPERS, BYREF_LESSTHAN, ByRefLessThan, NoSig)
DEFINE_METHOD(JIT_HELPERS, GET_ARRAY_DATA, GetArrayData, NoSig)
DEFINE_METHOD(JIT_HELPERS, CONTAINSREFERENCES, ContainsReferences, NoSig)
#endif

#ifdef FEATURE_SPAN_OF_T
Expand Down

0 comments on commit 3f98990

Please sign in to comment.