<CompilerServicesSources Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\TypeDependencyAttribute.cs" />
<CompilerServicesSources Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\CompilerMarshalOverride.cs" />
<CompilerServicesSources Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\jithelpers.cs" />
+ <CompilerServicesSources Condition="'$(FeatureSpanOfT)' == 'true'" Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\Unsafe.cs" />
<CompilerServicesSources Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\SpecialNameAttribute.cs" />
<CompilerServicesSources Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\SuppressMergeCheckAttribute.cs" />
<CompilerServicesSources Condition="'$(FeatureICastable)' == 'true'" Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\ICastable.cs" />
if ((uint)start >= (uint)array.Length || (uint)length > (uint)(array.Length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
- JitHelpers.SetByRef(out _rawPointer, ref JitHelpers.AddByRef(ref JitHelpers.GetArrayData(array), start));
+ JitHelpers.SetByRef(out _rawPointer, ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
_length = length;
}
public static implicit operator ReadOnlySpan<T>(Span<T> slice)
{
- return new ReadOnlySpan<T>(ref JitHelpers.GetByRef<T>(ref slice._rawPointer), slice.Length);
+ return new ReadOnlySpan<T>(ref JitHelpers.GetByRef<T>(ref slice._rawPointer), slice._length);
}
public static implicit operator ReadOnlySpan<T>(T[] array)
if ((uint)index >= (uint)_length)
ThrowHelper.ThrowIndexOutOfRangeException();
- return JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), index);
+ return Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), index);
}
}
/// </summary>
public T[] ToArray()
{
+ if (_length == 0)
+ return Array.Empty<T>();
+
var destination = new T[_length];
- TryCopyTo(destination);
+ SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref JitHelpers.GetByRef<T>(ref _rawPointer), _length);
return destination;
}
if ((uint)start > (uint)_length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new ReadOnlySpan<T>(ref JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), Length - start);
+ return new ReadOnlySpan<T>(ref Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), _length - start);
}
/// <summary>
if ((uint)start >= (uint)_length || (uint)length > (uint)(_length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new ReadOnlySpan<T>(ref JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), length);
+ return new ReadOnlySpan<T>(ref Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), length);
}
/// <summary>
public bool Equals(ReadOnlySpan<T> other)
{
return (_length == other._length) &&
- (_length == 0 || JitHelpers.ByRefEquals(ref JitHelpers.GetByRef<T>(ref _rawPointer), ref JitHelpers.GetByRef<T>(ref other._rawPointer)));
+ (_length == 0 || Unsafe.AreSame(ref JitHelpers.GetByRef<T>(ref _rawPointer), ref JitHelpers.GetByRef<T>(ref other._rawPointer)));
}
/// <summary>
/// <param name="destination">The span to copy items into.</param>
public bool TryCopyTo(Span<T> destination)
{
- if (Length > destination.Length)
+ if (_length > destination._length)
return false;
- SpanHelper.CopyTo<T>(ref destination._rawPointer, ref _rawPointer, Length);
+ SpanHelper.CopyTo<T>(ref JitHelpers.GetByRef<T>(ref destination._rawPointer), ref JitHelpers.GetByRef<T>(ref _rawPointer), _length);
return true;
}
}
if ((uint)start > (uint)text.Length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new ReadOnlySpan<char>(ref JitHelpers.AddByRef(ref text.GetFirstCharRef(), start), text.Length - start);
+ return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetFirstCharRef(), start), text.Length - start);
}
/// <summary>
if ((uint)start >= (uint)text.Length || (uint)length > (uint)(text.Length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new ReadOnlySpan<char>(ref JitHelpers.AddByRef(ref text.GetFirstCharRef(), start), length);
+ return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetFirstCharRef(), start), length);
}
}
-}
\ No newline at end of file
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.Versioning;
+
+namespace System.Runtime.CompilerServices
+{
+ //
+ // Subsetted clone of System.Runtime.CompilerServices.Unsafe for internal runtime use.
+ // Keep in sync with https://github.com/dotnet/corefx/tree/master/src/System.Runtime.CompilerServices.Unsafe.
+ //
+
+ /// <summary>
+ /// Contains generic, low-level functionality for manipulating pointers.
+ /// </summary>
+ internal static class Unsafe
+ {
+ /// <summary>
+ /// Returns the size of an object of the given type parameter.
+ /// </summary>
+ [NonVersionable]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int SizeOf<T>()
+ {
+ // The body of this function will be replaced by the EE with unsafe code that just returns sizeof !!T
+ // See getILIntrinsicImplementation for how this happens.
+ throw new InvalidOperationException();
+ }
+
+ /// <summary>
+ /// Reinterprets the given reference as a reference to a value of type <typeparamref name="TTo"/>.
+ /// </summary>
+ [NonVersionable]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref TTo As<TFrom, TTo>(ref TFrom source)
+ {
+ // The body of this function will be replaced by the EE with unsafe code that just returns sizeof !!T
+ // See getILIntrinsicImplementation for how this happens.
+ throw new InvalidOperationException();
+ }
+
+ /// <summary>
+ /// Adds an element offset to the given reference.
+ /// </summary>
+ [NonVersionable]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T Add<T>(ref T source, int elementOffset)
+ {
+ // The body of this function will be replaced by the EE with unsafe code!!!
+ // See getILIntrinsicImplementation for how this happens.
+ typeof(T).ToString(); // Type used by the actual method body
+ throw new InvalidOperationException();
+ }
+
+ /// <summary>
+ /// Determines whether the specified references point to the same location.
+ /// </summary>
+ [NonVersionable]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool AreSame<T>(ref T left, ref T right)
+ {
+ // The body of this function will be replaced by the EE with unsafe code!!!
+ // See getILIntrinsicImplementation for how this happens.
+ throw new InvalidOperationException();
+ }
+ }
+}
throw new InvalidOperationException();
}
- static internal ref T AddByRef<T>(ref T pointer, int count)
- {
- // The body of this function will be replaced by the EE with unsafe code!!!
- // See getILIntrinsicImplementation for how this happens.
- typeof(T).ToString(); // Type used by the actual method body
- throw new InvalidOperationException();
- }
-
- static internal bool ByRefEquals<T>(ref T refA, ref T refB)
- {
- // 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 bool ByRefLessThan<T>(ref T refA, ref T refB)
{
// The body of this function will be replaced by the EE with unsafe code!!!
throw new InvalidOperationException();
}
- static internal int SizeOf<T>()
- {
- // The body of this function will be replaced by the EE with unsafe code that just returns sizeof !!T
- // See getILIntrinsicImplementation for how this happens.
- throw new InvalidOperationException();
- }
-
/// <returns>true if given type is reference type or value type that contains references</returns>
static internal bool ContainsReferences<T>()
{
if ((uint)start >= (uint)array.Length || (uint)length > (uint)(array.Length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
- JitHelpers.SetByRef(out _rawPointer, ref JitHelpers.AddByRef(ref JitHelpers.GetArrayData(array), start));
+ JitHelpers.SetByRef(out _rawPointer, ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
_length = length;
}
if ((uint)index >= (uint)_length)
ThrowHelper.ThrowIndexOutOfRangeException();
- return JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), index);
+ return Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), index);
}
set
{
if ((uint)index >= (uint)_length)
ThrowHelper.ThrowIndexOutOfRangeException();
- JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), index) = value;
+ Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), index) = value;
}
}
/// </summary>
public T[] ToArray()
{
+ if (_length == 0)
+ return Array.Empty<T>();
+
var destination = new T[_length];
- TryCopyTo(destination);
+ SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref JitHelpers.GetByRef<T>(ref _rawPointer), _length);
return destination;
}
if ((uint)start > (uint)_length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new Span<T>(ref JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), Length - start);
+ return new Span<T>(ref Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), _length - start);
}
/// <summary>
if ((uint)start >= (uint)_length || (uint)length > (uint)(_length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new Span<T>(ref JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), length);
+ return new Span<T>(ref Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), length);
}
/// <summary>
public bool Equals(Span<T> other)
{
return (_length == other._length) &&
- (_length == 0 || JitHelpers.ByRefEquals(ref JitHelpers.GetByRef<T>(ref _rawPointer), ref JitHelpers.GetByRef<T>(ref other._rawPointer)));
+ (_length == 0 || Unsafe.AreSame(ref JitHelpers.GetByRef<T>(ref _rawPointer), ref JitHelpers.GetByRef<T>(ref other._rawPointer)));
}
/// <summary>
if (Length > destination.Length)
return false;
- SpanHelper.CopyTo<T>(ref destination._rawPointer, ref _rawPointer, Length);
+ SpanHelper.CopyTo<T>(ref JitHelpers.GetByRef<T>(ref destination._rawPointer), ref JitHelpers.GetByRef<T>(ref _rawPointer), _length);
return true;
}
if ((uint)values._length > (uint)_length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- SpanHelper.CopyTo<T>(ref _rawPointer, ref values._rawPointer, values.Length);
+ SpanHelper.CopyTo<T>(ref JitHelpers.GetByRef<T>(ref _rawPointer), ref JitHelpers.GetByRef<T>(ref values._rawPointer), values._length);
}
}
return new Span<byte>(
ref JitHelpers.GetByRef<byte>(ref source._rawPointer),
- checked((int)(source._length * JitHelpers.SizeOf<T>())));
+ checked((int)(source._length * Unsafe.SizeOf<T>())));
}
/// <summary>
return new ReadOnlySpan<byte>(
ref JitHelpers.GetByRef<byte>(ref source._rawPointer),
- checked((int)(source._length * JitHelpers.SizeOf<T>())));
+ checked((int)(source._length * Unsafe.SizeOf<T>())));
}
/// <summary>
return new Span<TTo>(
ref JitHelpers.GetByRef<TTo>(ref source._rawPointer),
- checked((int)(source._length * JitHelpers.SizeOf<TFrom>() / JitHelpers.SizeOf<TTo>())));
+ checked((int)(source._length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
}
/// <summary>
return new ReadOnlySpan<TTo>(
ref JitHelpers.GetByRef<TTo>(ref source._rawPointer),
- checked((int)(source._length * JitHelpers.SizeOf<TFrom>() / JitHelpers.SizeOf<TTo>())));
+ checked((int)(source._length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
}
}
internal static class SpanHelper
{
- internal static void CopyTo<T>(ref IntPtr destination, ref IntPtr source, int elementsCount)
+ internal static unsafe void CopyTo<T>(ref T destination, ref T source, int elementsCount)
{
if (elementsCount == 0)
return;
- ref T dest = ref JitHelpers.GetByRef<T>(ref destination);
- ref T src = ref JitHelpers.GetByRef<T>(ref source);
- if (JitHelpers.ByRefEquals(ref dest, ref src))
+ if (Unsafe.AreSame(ref destination, ref source))
return;
if (!JitHelpers.ContainsReferences<T>())
{
- unsafe
+ fixed (byte* pDestination = &Unsafe.As<T, byte>(ref destination))
{
- Memmove<T>((byte*)destination, (byte*)source, elementsCount);
+ fixed (byte* pSource = &Unsafe.As<T, byte>(ref source))
+ {
+#if BIT64
+ Buffer.Memmove(pDestination, pSource, (ulong)elementsCount * (ulong)Unsafe.SizeOf<T>());
+#else
+ Buffer.Memmove(pDestination, pSource, (uint)elementsCount * (uint)Unsafe.SizeOf<T>());
+#endif
+ }
}
}
else
{
- if (JitHelpers.ByRefLessThan(ref dest, ref src)) // copy forward
+ if (JitHelpers.ByRefLessThan(ref destination, ref source)) // copy forward
{
for (int i = 0; i < elementsCount; i++)
- JitHelpers.AddByRef(ref dest, i) = JitHelpers.AddByRef(ref src, i);
+ Unsafe.Add(ref destination, i) = Unsafe.Add(ref source, i);
}
else // copy backward to avoid overlapping issues
{
for (int i = elementsCount - 1; i >= 0; i--)
- JitHelpers.AddByRef(ref dest, i) = JitHelpers.AddByRef(ref src, i);
+ Unsafe.Add(ref destination, i) = Unsafe.Add(ref source, i);
}
}
}
-
- private static unsafe void Memmove<T>(byte* destination, byte* source, int elementsCount)
- {
-#if BIT64
- Buffer.Memmove(destination, source, (ulong)elementsCount * (ulong)JitHelpers.SizeOf<T>());
-#else
- Buffer.Memmove(destination, source, (uint)elementsCount * (uint)JitHelpers.SizeOf<T>());
-#endif
- }
}
-}
\ No newline at end of file
+}
methInfo->options = (CorInfoOptions)0;
return true;
}
- else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__ADD_BYREF)->GetMemberDef())
- {
- mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
-
- static BYTE ilcode[] = { CEE_LDARG_1,
- CEE_PREFIX1,(BYTE)CEE_SIZEOF,0,0,0,0,
- CEE_CONV_I,
- CEE_MUL,
- CEE_LDARG_0,
- CEE_ADD,
- CEE_RET };
-
- ilcode[3] = (BYTE)(tokGenericArg);
- ilcode[4] = (BYTE)(tokGenericArg >> 8);
- ilcode[5] = (BYTE)(tokGenericArg >> 16);
- ilcode[6] = (BYTE)(tokGenericArg >> 24);
-
- methInfo->ILCode = const_cast<BYTE*>(ilcode);
- methInfo->ILCodeSize = sizeof(ilcode);
- methInfo->maxStack = 2;
- methInfo->EHcount = 0;
- methInfo->options = (CorInfoOptions)0;
- return true;
- }
- else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__BYREF_EQUALS)->GetMemberDef())
- {
- // Compare the two arguments
- static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (BYTE)CEE_CEQ, CEE_RET };
- methInfo->ILCode = const_cast<BYTE*>(ilcode);
- methInfo->ILCodeSize = sizeof(ilcode);
- methInfo->maxStack = 2;
- methInfo->EHcount = 0;
- methInfo->options = (CorInfoOptions)0;
- return true;
- }
else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__BYREF_LESSTHAN)->GetMemberDef())
{
// Compare the two arguments
methInfo->options = (CorInfoOptions)0;
return true;
}
- else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__SIZEOF)->GetMemberDef())
- {
- _ASSERTE(ftn->HasMethodInstantiation());
- Instantiation inst = ftn->GetMethodInstantiation();
-
- _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
- mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
-
- static const BYTE ilcode[] = { CEE_PREFIX1, (BYTE)CEE_SIZEOF, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
- CEE_RET };
-
- methInfo->ILCode = const_cast<BYTE*>(ilcode);
- methInfo->ILCodeSize = sizeof(ilcode);
- methInfo->maxStack = 1;
- methInfo->EHcount = 0;
- methInfo->options = (CorInfoOptions)0;
- return true;
- }
else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__CONTAINSREFERENCES)->GetMemberDef())
{
_ASSERTE(ftn->HasMethodInstantiation());
methInfo->options = (CorInfoOptions)0;
return true;
}
-#endif
+#endif // FEATURE_SPAN_OF_T
return false;
}
+#ifdef FEATURE_SPAN_OF_T
+bool getILIntrinsicImplementationForUnsafe(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__UNSAFE__SIZEOF)->GetMemberDef())
+ {
+ _ASSERTE(ftn->HasMethodInstantiation());
+ Instantiation inst = ftn->GetMethodInstantiation();
+
+ _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
+ mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
+
+ static const BYTE ilcode[] = { CEE_PREFIX1, (BYTE)CEE_SIZEOF, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
+ CEE_RET };
+
+ methInfo->ILCode = const_cast<BYTE*>(ilcode);
+ methInfo->ILCodeSize = sizeof(ilcode);
+ methInfo->maxStack = 1;
+ methInfo->EHcount = 0;
+ methInfo->options = (CorInfoOptions)0;
+ return true;
+ }
+ else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef())
+ {
+ // Return the argument that was passed in.
+ static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
+ methInfo->ILCode = const_cast<BYTE*>(ilcode);
+ methInfo->ILCodeSize = sizeof(ilcode);
+ methInfo->maxStack = 1;
+ methInfo->EHcount = 0;
+ methInfo->options = (CorInfoOptions)0;
+ return true;
+ }
+ else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD)->GetMemberDef())
+ {
+ mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
+
+ static BYTE ilcode[] = { CEE_LDARG_1,
+ CEE_PREFIX1,(BYTE)CEE_SIZEOF,0,0,0,0,
+ CEE_CONV_I,
+ CEE_MUL,
+ CEE_LDARG_0,
+ CEE_ADD,
+ CEE_RET };
+
+ ilcode[3] = (BYTE)(tokGenericArg);
+ ilcode[4] = (BYTE)(tokGenericArg >> 8);
+ ilcode[5] = (BYTE)(tokGenericArg >> 16);
+ ilcode[6] = (BYTE)(tokGenericArg >> 24);
+
+ methInfo->ILCode = const_cast<BYTE*>(ilcode);
+ methInfo->ILCodeSize = sizeof(ilcode);
+ methInfo->maxStack = 2;
+ methInfo->EHcount = 0;
+ methInfo->options = (CorInfoOptions)0;
+ return true;
+ }
+ else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ARE_SAME)->GetMemberDef())
+ {
+ // Compare the two arguments
+ static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (BYTE)CEE_CEQ, CEE_RET };
+ methInfo->ILCode = const_cast<BYTE*>(ilcode);
+ methInfo->ILCodeSize = sizeof(ilcode);
+ methInfo->maxStack = 2;
+ methInfo->EHcount = 0;
+ methInfo->options = (CorInfoOptions)0;
+ return true;
+ }
+
+ return false;
+}
+#endif // FEATURE_SPAN_OF_T
+
bool getILIntrinsicImplementationForVolatile(MethodDesc * ftn,
CORINFO_METHOD_INFO * methInfo)
{
{
fILIntrinsic = getILIntrinsicImplementation(ftn, methInfo);
}
+#ifdef FEATURE_SPAN_OF_T
+ else if (MscorlibBinder::IsClass(pMT, CLASS__UNSAFE))
+ {
+ fILIntrinsic = getILIntrinsicImplementationForUnsafe(ftn, methInfo);
+ }
+#endif
else if (MscorlibBinder::IsClass(pMT, CLASS__INTERLOCKED))
{
fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
#ifdef FEATURE_SPAN_OF_T
DEFINE_METHOD(JIT_HELPERS, GET_BYREF, GetByRef, NoSig)
DEFINE_METHOD(JIT_HELPERS, SET_BYREF, SetByRef, NoSig)
-DEFINE_METHOD(JIT_HELPERS, ADD_BYREF, AddByRef, NoSig)
-DEFINE_METHOD(JIT_HELPERS, BYREF_EQUALS, ByRefEquals, NoSig)
DEFINE_METHOD(JIT_HELPERS, BYREF_LESSTHAN, ByRefLessThan, NoSig)
DEFINE_METHOD(JIT_HELPERS, GET_ARRAY_DATA, GetArrayData, NoSig)
-DEFINE_METHOD(JIT_HELPERS, SIZEOF, SizeOf, NoSig)
DEFINE_METHOD(JIT_HELPERS, CONTAINSREFERENCES, ContainsReferences, NoSig)
#endif
+#ifdef FEATURE_SPAN_OF_T
+DEFINE_CLASS(UNSAFE, CompilerServices, Unsafe)
+DEFINE_METHOD(UNSAFE, SIZEOF, SizeOf, NoSig)
+DEFINE_METHOD(UNSAFE, BYREF_AS, As, NoSig)
+DEFINE_METHOD(UNSAFE, BYREF_ADD, Add, NoSig)
+DEFINE_METHOD(UNSAFE, BYREF_ARE_SAME, AreSame, NoSig)
+#endif
+
DEFINE_CLASS(INTERLOCKED, Threading, Interlocked)
DEFINE_METHOD(INTERLOCKED, COMPARE_EXCHANGE_T, CompareExchange, GM_RefT_T_T_RetT)
DEFINE_METHOD(INTERLOCKED, COMPARE_EXCHANGE_OBJECT,CompareExchange, SM_RefObject_Object_Object_RetObject)