From 3b8e6b1220c793e47c5ac8eb2afef435081f8a4e Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sun, 12 Feb 2017 11:00:22 -0800 Subject: [PATCH] Add RuntimeHelpers.IsReferenceOrContainsReferences() Rename JitHelpers.ContainsReferences() to RuntimeHelpers.IsReferenceOrContainsReferences() and make it public. Work towards https://github.com/dotnet/corefx/issues/14047 --- .../src/System/Collections/Generic/List.cs | 21 +++--- src/mscorlib/src/System/ReadOnlySpan.cs | 2 +- .../CompilerServices/RuntimeHelpers.cs | 8 +++ .../Runtime/CompilerServices/jithelpers.cs | 8 --- src/mscorlib/src/System/Span.cs | 16 ++--- src/vm/jitinterface.cpp | 72 ++++++++++++------- src/vm/mscorlib.h | 2 +- 7 files changed, 74 insertions(+), 55 deletions(-) diff --git a/src/mscorlib/src/System/Collections/Generic/List.cs b/src/mscorlib/src/System/Collections/Generic/List.cs index 8e154d748f8c..82f6e41c361e 100644 --- a/src/mscorlib/src/System/Collections/Generic/List.cs +++ b/src/mscorlib/src/System/Collections/Generic/List.cs @@ -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 @@ -292,7 +293,7 @@ public int BinarySearch(T item, IComparer comparer) // Clears the contents of List. public void Clear() { - if (JitHelpers.ContainsReferences()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) { int size = _size; _size = 0; @@ -863,7 +864,7 @@ public int RemoveAll(Predicate match) { } } - if (JitHelpers.ContainsReferences()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) { Array.Clear(_items, freeIndex, _size - freeIndex); // Clear the elements so that the gc can reclaim the references. } @@ -887,7 +888,7 @@ public void RemoveAt(int index) { { Array.Copy(_items, index + 1, _items, index, _size - index); } - if (JitHelpers.ContainsReferences()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) { _items[_size] = default(T); } @@ -917,7 +918,7 @@ public void RemoveRange(int index, int count) { } _version++; - if (JitHelpers.ContainsReferences()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) { Array.Clear(_items, _size, count); } diff --git a/src/mscorlib/src/System/ReadOnlySpan.cs b/src/mscorlib/src/System/ReadOnlySpan.cs index 76c63d5d8beb..ccbca3c118dd 100644 --- a/src/mscorlib/src/System/ReadOnlySpan.cs +++ b/src/mscorlib/src/System/ReadOnlySpan.cs @@ -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()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); if (length < 0) ThrowHelper.ThrowArgumentOutOfRangeException(); diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index 509e527ecb0d..980c2fd46973 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -167,6 +167,14 @@ internal static void ExecuteBackoutCodeHelper(Object backoutCode, Object userDat { ((CleanupCode)backoutCode)(userData, exceptionThrown); } + + /// true if given type is reference type or value type that contains references + static public bool IsReferenceOrContainsReferences() + { + // The body of this function will be replaced by the EE with unsafe code!!! + // See getILIntrinsicImplementation for how this happens. + throw new InvalidOperationException(); + } } } diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs index 080e42f46f12..8f847827aa9f 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs @@ -223,14 +223,6 @@ static internal bool ByRefLessThan(ref T refA, ref T refB) throw new InvalidOperationException(); } - /// true if given type is reference type or value type that contains references - static internal bool ContainsReferences() - { - // 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[] array) { // The body of this function will be replaced by the EE with unsafe code!!! diff --git a/src/mscorlib/src/System/Span.cs b/src/mscorlib/src/System/Span.cs index c77a1994c97b..b0d5771c10b4 100644 --- a/src/mscorlib/src/System/Span.cs +++ b/src/mscorlib/src/System/Span.cs @@ -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()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); if (length < 0) ThrowHelper.ThrowArgumentOutOfRangeException(); @@ -451,7 +451,7 @@ public static class Span public static Span AsBytes(this Span source) where T : struct { - if (JitHelpers.ContainsReferences()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); return new Span( @@ -470,7 +470,7 @@ ref Unsafe.As(ref source.DangerousGetPinnableReference()), public static ReadOnlySpan AsBytes(this ReadOnlySpan source) where T : struct { - if (JitHelpers.ContainsReferences()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); return new ReadOnlySpan( @@ -493,9 +493,9 @@ public static Span NonPortableCast(this Span source) where TFrom : struct where TTo : struct { - if (JitHelpers.ContainsReferences()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom)); - if (JitHelpers.ContainsReferences()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo)); return new Span( @@ -518,9 +518,9 @@ public static ReadOnlySpan NonPortableCast(this ReadOnlySpan()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom)); - if (JitHelpers.ContainsReferences()) + if (RuntimeHelpers.IsReferenceOrContainsReferences()) ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo)); return new ReadOnlySpan( @@ -597,7 +597,7 @@ internal static unsafe void CopyTo(ref T destination, ref T source, int eleme if (Unsafe.AreSame(ref destination, ref source)) return; - if (!JitHelpers.ContainsReferences()) + if (!RuntimeHelpers.IsReferenceOrContainsReferences()) { fixed (byte* pDestination = &Unsafe.As(ref destination)) { diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp index d84dbbb53c02..8a0e0f9c0673 100644 --- a/src/vm/jitinterface.cpp +++ b/src/vm/jitinterface.cpp @@ -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(returnTrue); - } - else - { - methInfo->ILCode = const_cast(returnFalse); - } - - methInfo->ILCodeSize = sizeof(returnTrue); - methInfo->maxStack = 1; - methInfo->EHcount = 0; - methInfo->options = (CorInfoOptions)0; - return true; - } #endif // FEATURE_SPAN_OF_T return false; @@ -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(returnTrue); + } + else + { + methInfo->ILCode = const_cast(returnFalse); + } + + methInfo->ILCodeSize = sizeof(returnTrue); + methInfo->maxStack = 1; + methInfo->EHcount = 0; + methInfo->options = (CorInfoOptions)0; + return true; + } + + return false; +} + //--------------------------------------------------------------------------------------- // //static @@ -7323,6 +7337,10 @@ getMethodInfoHelper( { fILIntrinsic = getILIntrinsicImplementationForVolatile(ftn, methInfo); } + else if (MscorlibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS)) + { + fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo); + } if (!fILIntrinsic) { diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h index 78eab6c7d3b0..8f20078068e1 100644 --- a/src/vm/mscorlib.h +++ b/src/vm/mscorlib.h @@ -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 @@ -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