diff --git a/src/inc/dacvars.h b/src/inc/dacvars.h
index 4df214203a24..0a60684ad13d 100644
--- a/src/inc/dacvars.h
+++ b/src/inc/dacvars.h
@@ -219,8 +219,7 @@ DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pArrayClass, ::g_pArrayClass)
DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pSZArrayHelperClass, ::g_pSZArrayHelperClass)
DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pNullableClass, ::g_pNullableClass)
#ifdef FEATURE_SPAN_OF_T
-DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pSpanClass, ::g_pSpanClass)
-DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pReadOnlySpanClass, ::g_pReadOnlySpanClass)
+DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pByReferenceClass, ::g_pByReferenceClass)
#endif
DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pExceptionClass, ::g_pExceptionClass)
DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pThreadAbortExceptionClass, ::g_pThreadAbortExceptionClass)
diff --git a/src/mscorlib/model.xml b/src/mscorlib/model.xml
index 92ef0d932d7b..b4cd2bdbbfd0 100644
--- a/src/mscorlib/model.xml
+++ b/src/mscorlib/model.xml
@@ -12406,6 +12406,7 @@
+
@@ -12425,6 +12426,7 @@
+
diff --git a/src/mscorlib/src/System/ReadOnlySpan.cs b/src/mscorlib/src/System/ReadOnlySpan.cs
index e94d3534fc3b..d32f8d8a6846 100644
--- a/src/mscorlib/src/System/ReadOnlySpan.cs
+++ b/src/mscorlib/src/System/ReadOnlySpan.cs
@@ -15,8 +15,8 @@ namespace System
///
public unsafe struct ReadOnlySpan
{
- /// A byref or a native ptr. Do not access directly
- private readonly IntPtr _rawPointer;
+ /// A byref or a native ptr.
+ private readonly ByReference _pointer;
/// The number of elements this ReadOnlySpan contains.
private readonly int _length;
@@ -31,8 +31,7 @@ public ReadOnlySpan(T[] array)
if (array == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- _rawPointer = (IntPtr)Unsafe.AsPointer(ref JitHelpers.GetArrayData(array));
+ _pointer = new ByReference(ref JitHelpers.GetArrayData(array));
_length = array.Length;
}
@@ -54,8 +53,7 @@ public ReadOnlySpan(T[] array, int start)
if ((uint)start > (uint)array.Length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- _rawPointer = (IntPtr)Unsafe.AsPointer(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
+ _pointer = new ByReference(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
_length = array.Length - start;
}
@@ -78,8 +76,7 @@ public ReadOnlySpan(T[] array, int start, int length)
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- _rawPointer = (IntPtr)Unsafe.AsPointer(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
+ _pointer = new ByReference(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
_length = length;
}
@@ -105,7 +102,7 @@ public unsafe ReadOnlySpan(void* pointer, int length)
if (length < 0)
ThrowHelper.ThrowArgumentOutOfRangeException();
- _rawPointer = (IntPtr)pointer;
+ _pointer = new ByReference(ref Unsafe.AsRef(pointer));
_length = length;
}
@@ -114,18 +111,17 @@ public unsafe ReadOnlySpan(void* pointer, int length)
///
internal ReadOnlySpan(ref T ptr, int length)
{
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- _rawPointer = (IntPtr)Unsafe.AsPointer(ref ptr);
+ _pointer = new ByReference(ref ptr);
_length = length;
}
///
- /// An internal helper for accessing spans.
+ /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
+ /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
///
- internal unsafe ref T GetRawPointer()
+ public unsafe ref T DangerousGetPinnableReference()
{
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- return ref Unsafe.As(ref *(IntPtr *)_rawPointer);
+ return ref _pointer.Value;
}
///
@@ -133,7 +129,7 @@ internal unsafe ref T GetRawPointer()
///
public static implicit operator ReadOnlySpan(Span slice)
{
- return new ReadOnlySpan(ref slice.GetRawPointer(), slice.Length);
+ return new ReadOnlySpan(ref slice.DangerousGetPinnableReference(), slice.Length);
}
///
@@ -189,7 +185,7 @@ public T this[int index]
if ((uint)index >= (uint)_length)
ThrowHelper.ThrowIndexOutOfRangeException();
- return Unsafe.Add(ref GetRawPointer(), index);
+ return Unsafe.Add(ref DangerousGetPinnableReference(), index);
}
}
@@ -204,7 +200,7 @@ public T[] ToArray()
return Array.Empty();
var destination = new T[_length];
- SpanHelper.CopyTo(ref JitHelpers.GetArrayData(destination), ref GetRawPointer(), _length);
+ SpanHelper.CopyTo(ref JitHelpers.GetArrayData(destination), ref DangerousGetPinnableReference(), _length);
return destination;
}
@@ -221,7 +217,7 @@ public ReadOnlySpan Slice(int start)
if ((uint)start > (uint)_length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new ReadOnlySpan(ref Unsafe.Add(ref GetRawPointer(), start), _length - start);
+ return new ReadOnlySpan(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), _length - start);
}
///
@@ -238,7 +234,7 @@ public ReadOnlySpan Slice(int start, int length)
if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new ReadOnlySpan(ref Unsafe.Add(ref GetRawPointer(), start), length);
+ return new ReadOnlySpan(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), length);
}
///
@@ -248,7 +244,7 @@ public ReadOnlySpan Slice(int start, int length)
public bool Equals(ReadOnlySpan other)
{
return (_length == other.Length) &&
- (_length == 0 || Unsafe.AreSame(ref GetRawPointer(), ref other.GetRawPointer()));
+ (_length == 0 || Unsafe.AreSame(ref DangerousGetPinnableReference(), ref other.DangerousGetPinnableReference()));
}
///
@@ -261,7 +257,7 @@ public bool TryCopyTo(Span destination)
if ((uint)_length > (uint)destination.Length)
return false;
- SpanHelper.CopyTo(ref destination.GetRawPointer(), ref GetRawPointer(), _length);
+ SpanHelper.CopyTo(ref destination.DangerousGetPinnableReference(), ref DangerousGetPinnableReference(), _length);
return true;
}
}
diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs
index 70d8ec079ab4..8889afa80fc4 100644
--- a/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs
+++ b/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs
@@ -40,6 +40,18 @@ public static int SizeOf()
throw new InvalidOperationException();
}
+ ///
+ /// Reinterprets the given location as a reference to a value of type.
+ ///
+ [NonVersionable]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T AsRef(void * source)
+ {
+ // The body of this function will be replaced by the EE with unsafe code that just returns sizeof !!T
+ // See getILIntrinsicImplementationForUnsafe for how this happens.
+ throw new InvalidOperationException();
+ }
+
///
/// Reinterprets the given reference as a reference to a value of type .
///
diff --git a/src/mscorlib/src/System/Span.cs b/src/mscorlib/src/System/Span.cs
index 2eff6ae8006b..b8e98cadd917 100644
--- a/src/mscorlib/src/System/Span.cs
+++ b/src/mscorlib/src/System/Span.cs
@@ -15,8 +15,8 @@ namespace System
///
public unsafe struct Span
{
- /// A byref or a native ptr. Do not access directly
- private readonly IntPtr _rawPointer;
+ /// A byref or a native ptr.
+ private readonly ByReference _pointer;
/// The number of elements this Span contains.
private readonly int _length;
@@ -36,8 +36,7 @@ public Span(T[] array)
ThrowHelper.ThrowArrayTypeMismatchException();
}
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- _rawPointer = (IntPtr)Unsafe.AsPointer(ref JitHelpers.GetArrayData(array));
+ _pointer = new ByReference(ref JitHelpers.GetArrayData(array));
_length = array.Length;
}
@@ -64,8 +63,7 @@ public Span(T[] array, int start)
if ((uint)start > (uint)array.Length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- _rawPointer = (IntPtr)Unsafe.AsPointer(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
+ _pointer = new ByReference(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
_length = array.Length - start;
}
@@ -93,8 +91,7 @@ public Span(T[] array, int start, int length)
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- _rawPointer = (IntPtr)Unsafe.AsPointer(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
+ _pointer = new ByReference(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
_length = length;
}
@@ -120,7 +117,7 @@ public unsafe Span(void* pointer, int length)
if (length < 0)
ThrowHelper.ThrowArgumentOutOfRangeException();
- _rawPointer = (IntPtr)pointer;
+ _pointer = new ByReference(ref Unsafe.AsRef(pointer));
_length = length;
}
@@ -129,18 +126,17 @@ public unsafe Span(void* pointer, int length)
///
internal Span(ref T ptr, int length)
{
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- _rawPointer = (IntPtr)Unsafe.AsPointer(ref ptr);
+ _pointer = new ByReference(ref ptr);
_length = length;
}
///
- /// An internal helper for accessing spans.
+ /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
+ /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
///
- internal unsafe ref T GetRawPointer()
+ public unsafe ref T DangerousGetPinnableReference()
{
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- return ref Unsafe.As(ref *(IntPtr*)_rawPointer);
+ return ref _pointer.Value;
}
///
@@ -196,14 +192,14 @@ public T this[int index]
if ((uint)index >= (uint)_length)
ThrowHelper.ThrowIndexOutOfRangeException();
- return Unsafe.Add(ref GetRawPointer(), index);
+ return Unsafe.Add(ref DangerousGetPinnableReference(), index);
}
set
{
if ((uint)index >= (uint)_length)
ThrowHelper.ThrowIndexOutOfRangeException();
- Unsafe.Add(ref GetRawPointer(), index) = value;
+ Unsafe.Add(ref DangerousGetPinnableReference(), index) = value;
}
}
@@ -218,7 +214,7 @@ public T[] ToArray()
return Array.Empty();
var destination = new T[_length];
- SpanHelper.CopyTo(ref JitHelpers.GetArrayData(destination), ref GetRawPointer(), _length);
+ SpanHelper.CopyTo(ref JitHelpers.GetArrayData(destination), ref DangerousGetPinnableReference(), _length);
return destination;
}
@@ -235,7 +231,7 @@ public Span Slice(int start)
if ((uint)start > (uint)_length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new Span(ref Unsafe.Add(ref GetRawPointer(), start), _length - start);
+ return new Span(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), _length - start);
}
///
@@ -252,7 +248,7 @@ public Span Slice(int start, int length)
if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new Span(ref Unsafe.Add(ref GetRawPointer(), start), length);
+ return new Span(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), length);
}
///
@@ -262,7 +258,7 @@ public Span Slice(int start, int length)
public bool Equals(Span other)
{
return (_length == other.Length) &&
- (_length == 0 || Unsafe.AreSame(ref GetRawPointer(), ref other.GetRawPointer()));
+ (_length == 0 || Unsafe.AreSame(ref DangerousGetPinnableReference(), ref other.DangerousGetPinnableReference()));
}
///
@@ -275,7 +271,7 @@ public bool TryCopyTo(Span destination)
if ((uint)_length > (uint)destination.Length)
return false;
- SpanHelper.CopyTo(ref destination.GetRawPointer(), ref GetRawPointer(), _length);
+ SpanHelper.CopyTo(ref destination.DangerousGetPinnableReference(), ref DangerousGetPinnableReference(), _length);
return true;
}
@@ -287,7 +283,7 @@ public void Set(ReadOnlySpan values)
if ((uint)values.Length > (uint)_length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- SpanHelper.CopyTo(ref GetRawPointer(), ref values.GetRawPointer(), values.Length);
+ SpanHelper.CopyTo(ref DangerousGetPinnableReference(), ref values.DangerousGetPinnableReference(), values.Length);
}
}
@@ -308,7 +304,7 @@ public static Span AsBytes(this Span source)
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
return new Span(
- ref Unsafe.As(ref source.GetRawPointer()),
+ ref Unsafe.As(ref source.DangerousGetPinnableReference()),
checked(source.Length * Unsafe.SizeOf()));
}
@@ -327,7 +323,7 @@ public static ReadOnlySpan AsBytes(this ReadOnlySpan source)
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
return new ReadOnlySpan(
- ref Unsafe.As(ref source.GetRawPointer()),
+ ref Unsafe.As(ref source.DangerousGetPinnableReference()),
checked(source.Length * Unsafe.SizeOf()));
}
@@ -352,7 +348,7 @@ public static unsafe Span NonPortableCast(this Span sour
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
return new Span(
- ref Unsafe.As(ref source.GetRawPointer()),
+ ref Unsafe.As(ref source.DangerousGetPinnableReference()),
checked((int)((long)source.Length * Unsafe.SizeOf() / Unsafe.SizeOf())));
}
@@ -377,7 +373,7 @@ public static unsafe ReadOnlySpan NonPortableCast(this ReadOnly
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
return new ReadOnlySpan(
- ref Unsafe.As(ref source.GetRawPointer()),
+ ref Unsafe.As(ref source.DangerousGetPinnableReference()),
checked((int)((long)source.Length * Unsafe.SizeOf() / Unsafe.SizeOf())));
}
}
@@ -421,4 +417,24 @@ internal static unsafe void CopyTo(ref T destination, ref T source, int eleme
}
}
}
+
+ internal unsafe struct ByReference
+ {
+ private IntPtr _value;
+
+ public ByReference(ref T value)
+ {
+ // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
+ _value = (IntPtr)Unsafe.AsPointer(ref value);
+ }
+
+ public ref T Value
+ {
+ get
+ {
+ // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
+ return ref Unsafe.As(ref *(IntPtr*)_value);
+ }
+ }
+ }
}
diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp
index 0ee260e3ef67..b7fc67cd2415 100644
--- a/src/vm/appdomain.cpp
+++ b/src/vm/appdomain.cpp
@@ -2871,9 +2871,8 @@ void SystemDomain::LoadBaseSystemClasses()
g_pSZArrayHelperClass = MscorlibBinder::GetClass(CLASS__SZARRAYHELPER);
#ifdef FEATURE_SPAN_OF_T
- // Load Span class
- g_pSpanClass = MscorlibBinder::GetClass(CLASS__SPAN);
- g_pReadOnlySpanClass = MscorlibBinder::GetClass(CLASS__READONLY_SPAN);
+ // Load ByReference class
+ g_pByReferenceClass = MscorlibBinder::GetClass(CLASS__BYREFERENCE);
#endif
// Load Nullable class
diff --git a/src/vm/classnames.h b/src/vm/classnames.h
index ec5486ac7a34..47f1fecdec13 100644
--- a/src/vm/classnames.h
+++ b/src/vm/classnames.h
@@ -17,8 +17,7 @@
#define g_NullableName "Nullable`1"
#ifdef FEATURE_SPAN_OF_T
-#define g_SpanName "Span`1"
-#define g_ReadOnlySpanName "ReadOnlySpan`1"
+#define g_ByReferenceName "ByReference`1"
#endif
#define g_CollectionsEnumerableItfName "System.Collections.IEnumerable"
diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
index fac4cb44f25f..5d1dfa7f2014 100644
--- a/src/vm/jitinterface.cpp
+++ b/src/vm/jitinterface.cpp
@@ -2303,13 +2303,9 @@ unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
MethodTable* pMT = VMClsHnd.GetMethodTable();
- if (pMT == g_TypedReferenceMT) // if (pMT->IsByRefLike()) // TODO-SPAN: Proper GC reporting
+ if (pMT->IsByRefLike())
{
- if (pMT == g_TypedReferenceMT
-#ifdef FEATURE_SPAN_OF_T
- || pMT->HasSameTypeDefAs(g_pSpanClass) || pMT->HasSameTypeDefAs(g_pReadOnlySpanClass)
-#endif
- )
+ if (pMT == g_TypedReferenceMT)
{
gcPtrs[0] = TYPE_GC_BYREF;
gcPtrs[1] = TYPE_GC_NONE;
@@ -2317,6 +2313,7 @@ unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
}
else
{
+ // TODO-SPAN: Proper GC reporting
result = 0;
}
}
@@ -7034,7 +7031,9 @@ bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
methInfo->options = (CorInfoOptions)0;
return true;
}
- else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef())
+ else if ((tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_REF)->GetMemberDef()) ||
+ (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef()))
+
{
// Return the argument that was passed in.
static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
diff --git a/src/vm/methodtablebuilder.cpp b/src/vm/methodtablebuilder.cpp
index ab55f11ced08..682268eb39b1 100644
--- a/src/vm/methodtablebuilder.cpp
+++ b/src/vm/methodtablebuilder.cpp
@@ -1862,6 +1862,11 @@ MethodTableBuilder::BuildMethodTableThrowing(
pMT->SetHasBoxedRegularStatics();
}
+ if (bmtFP->fIsByRefLikeType)
+ {
+ pMT->SetIsByRefLike();
+ }
+
if (IsValueClass())
{
if (bmtFP->NumInstanceFieldBytes != totalDeclaredFieldSize || HasOverLayedField())
@@ -4214,14 +4219,12 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
goto GOT_ELEMENT_TYPE;
}
- // There are just few types with code:IsByRefLike set - see code:CheckForSystemTypes.
- // Note: None of them will ever have self-referencing static ValueType field (we cannot assert it now because the IsByRefLike
- // status for this type has not been initialized yet).
+ // Inherit IsByRefLike characteristic from fields
if (!IsSelfRef(pByValueClass) && pByValueClass->IsByRefLike())
- { // Cannot have embedded valuetypes that contain a field that require stack allocation.
- BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
+ {
+ bmtFP->fIsByRefLikeType = true;
}
-
+
if (!IsSelfRef(pByValueClass) && pByValueClass->GetClass()->HasNonPublicFields())
{ // If a class has a field of type ValueType with non-public fields in it,
// the class must "inherit" this characteristic
@@ -10207,19 +10210,10 @@ void MethodTableBuilder::CheckForSystemTypes()
if (bmtGenerics->HasInstantiation() && g_pNullableClass != NULL)
{
#ifdef FEATURE_SPAN_OF_T
- _ASSERTE(g_pSpanClass != NULL);
- _ASSERTE(g_pReadOnlySpanClass != NULL);
-
- _ASSERTE(g_pSpanClass->IsByRefLike());
- _ASSERTE(g_pReadOnlySpanClass->IsByRefLike());
+ _ASSERTE(g_pByReferenceClass != NULL);
+ _ASSERTE(g_pByReferenceClass->IsByRefLike());
- if (GetCl() == g_pSpanClass->GetCl())
- {
- pMT->SetIsByRefLike();
- return;
- }
-
- if (GetCl() == g_pReadOnlySpanClass->GetCl())
+ if (GetCl() == g_pByReferenceClass->GetCl())
{
pMT->SetIsByRefLike();
return;
@@ -10281,11 +10275,7 @@ void MethodTableBuilder::CheckForSystemTypes()
pMT->SetIsNullable();
}
#ifdef FEATURE_SPAN_OF_T
- else if (strcmp(name, g_SpanName) == 0)
- {
- pMT->SetIsByRefLike();
- }
- else if (strcmp(name, g_ReadOnlySpanName) == 0)
+ else if (strcmp(name, g_ByReferenceName) == 0)
{
pMT->SetIsByRefLike();
}
diff --git a/src/vm/methodtablebuilder.h b/src/vm/methodtablebuilder.h
index 1e40ea996c45..1cf71499e627 100644
--- a/src/vm/methodtablebuilder.h
+++ b/src/vm/methodtablebuilder.h
@@ -2081,6 +2081,7 @@ class MethodTableBuilder
DWORD NumGCPointerSeries;
DWORD NumInstanceFieldBytes;
+ bool fIsByRefLikeType;
bool fHasFixedAddressValueTypes;
bool fHasSelfReferencingStaticValueTypeField_WithRVA;
diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h
index c145e4deff1c..7a0b1a04f144 100644
--- a/src/vm/mscorlib.h
+++ b/src/vm/mscorlib.h
@@ -1053,6 +1053,7 @@ DEFINE_FIELD(NULL, VALUE, Value)
DEFINE_CLASS(NULLABLE, System, Nullable`1)
#ifdef FEATURE_SPAN_OF_T
+DEFINE_CLASS(BYREFERENCE, System, ByReference`1)
DEFINE_CLASS(SPAN, System, Span`1)
DEFINE_CLASS(READONLY_SPAN, System, ReadOnlySpan`1)
#endif
@@ -1352,6 +1353,7 @@ DEFINE_METHOD(JIT_HELPERS, CONTAINSREFERENCES, ContainsReferences,
DEFINE_CLASS(UNSAFE, CompilerServices, Unsafe)
DEFINE_METHOD(UNSAFE, AS_POINTER, AsPointer, NoSig)
DEFINE_METHOD(UNSAFE, SIZEOF, SizeOf, NoSig)
+DEFINE_METHOD(UNSAFE, AS_REF, AsRef, NoSig)
DEFINE_METHOD(UNSAFE, BYREF_AS, As, NoSig)
DEFINE_METHOD(UNSAFE, BYREF_ADD, Add, NoSig)
DEFINE_METHOD(UNSAFE, BYREF_ARE_SAME, AreSame, NoSig)
diff --git a/src/vm/vars.cpp b/src/vm/vars.cpp
index 8d19a5c20e1d..626ca3c9d319 100644
--- a/src/vm/vars.cpp
+++ b/src/vm/vars.cpp
@@ -70,8 +70,7 @@ GPTR_IMPL(MethodTable, g_pArrayClass);
GPTR_IMPL(MethodTable, g_pSZArrayHelperClass);
GPTR_IMPL(MethodTable, g_pNullableClass);
#ifdef FEATURE_SPAN_OF_T
-GPTR_IMPL(MethodTable, g_pSpanClass);
-GPTR_IMPL(MethodTable, g_pReadOnlySpanClass);
+GPTR_IMPL(MethodTable, g_pByReferenceClass);
#endif
GPTR_IMPL(MethodTable, g_pExceptionClass);
GPTR_IMPL(MethodTable, g_pThreadAbortExceptionClass);
diff --git a/src/vm/vars.hpp b/src/vm/vars.hpp
index 712543c2b15c..62d6656eaf10 100644
--- a/src/vm/vars.hpp
+++ b/src/vm/vars.hpp
@@ -403,8 +403,7 @@ GPTR_DECL(MethodTable, g_pArrayClass);
GPTR_DECL(MethodTable, g_pSZArrayHelperClass);
GPTR_DECL(MethodTable, g_pNullableClass);
#ifdef FEATURE_SPAN_OF_T
-GPTR_DECL(MethodTable, g_pSpanClass);
-GPTR_DECL(MethodTable, g_pReadOnlySpanClass);
+GPTR_DECL(MethodTable, g_pByReferenceClass);
#endif
GPTR_DECL(MethodTable, g_pExceptionClass);
GPTR_DECL(MethodTable, g_pThreadAbortExceptionClass);