summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kotas <jkotas@microsoft.com>2016-12-07 15:16:57 -0800
committerGitHub <noreply@github.com>2016-12-07 15:16:57 -0800
commit64c2ad17351ac5bc0bb042216bfcbf1c5136d7cf (patch)
treebbbec792192a88f2afe1e126f0ca4d0050348e32
parentbea2a8cf3d1ffe90683c47758f27f7cc83850982 (diff)
downloadcoreclr-64c2ad17351ac5bc0bb042216bfcbf1c5136d7cf.tar.gz
coreclr-64c2ad17351ac5bc0bb042216bfcbf1c5136d7cf.tar.bz2
coreclr-64c2ad17351ac5bc0bb042216bfcbf1c5136d7cf.zip
Refactor Span<T> to ease implementation of JIT intrinsics (#8497)
- Introduce internal ByReference<T> type for byref fields and change Span to use it - Generalize handling of byref-like types in the type loader - Make DangerousGetPinnableReference public while I was on it
-rw-r--r--src/inc/dacvars.h3
-rw-r--r--src/mscorlib/model.xml2
-rw-r--r--src/mscorlib/mscorlib.shared.sources.props1
-rw-r--r--src/mscorlib/src/System/ByReference.cs31
-rw-r--r--src/mscorlib/src/System/ReadOnlySpan.cs42
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs16
-rw-r--r--src/mscorlib/src/System/Span.cs56
-rw-r--r--src/vm/appdomain.cpp5
-rw-r--r--src/vm/classnames.h3
-rw-r--r--src/vm/jitinterface.cpp15
-rw-r--r--src/vm/methodtablebuilder.cpp36
-rw-r--r--src/vm/methodtablebuilder.h1
-rw-r--r--src/vm/mscorlib.h2
-rw-r--r--src/vm/vars.cpp3
-rw-r--r--src/vm/vars.hpp3
15 files changed, 123 insertions, 96 deletions
diff --git a/src/inc/dacvars.h b/src/inc/dacvars.h
index 4df214203a..0a60684ad1 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 92ef0d932d..b4cd2bdbbf 100644
--- a/src/mscorlib/model.xml
+++ b/src/mscorlib/model.xml
@@ -12406,6 +12406,7 @@
<Member Name="#ctor(T[],System.Int32)" />
<Member Name="#ctor(T[],System.Int32,System.Int32)" />
<Member Name="#ctor(System.Void*,System.Int32)" />
+ <Member Name="DangerousGetPinnableReference" />
<Member Name="op_Implicit(T[])" ReturnType="System.Span&lt;T&gt;" />
<Member Name="op_Implicit(System.ArraySegment&lt;T&gt;)" ReturnType="System.Span&lt;T&gt;" />
<Member Name="get_Length" />
@@ -12425,6 +12426,7 @@
<Member Name="#ctor(T[],System.Int32)" />
<Member Name="#ctor(T[],System.Int32,System.Int32)" />
<Member Name="#ctor(System.Void*,System.Int32)" />
+ <Member Name="DangerousGetPinnableReference" />
<Member Name="op_Implicit(System.Span&lt;T&gt;)" ReturnType="System.ReadOnlySpan&lt;T&gt;" />
<Member Name="op_Implicit(T[])" ReturnType="System.ReadOnlySpan&lt;T&gt;" />
<Member Name="op_Implicit(System.ArraySegment&lt;T&gt;)" ReturnType="System.ReadOnlySpan&lt;T&gt;" />
diff --git a/src/mscorlib/mscorlib.shared.sources.props b/src/mscorlib/mscorlib.shared.sources.props
index 891f73c055..8d4142ea62 100644
--- a/src/mscorlib/mscorlib.shared.sources.props
+++ b/src/mscorlib/mscorlib.shared.sources.props
@@ -438,6 +438,7 @@
<SystemSources Condition="'$(FeatureCominterop)' == 'true'" Include="$(BclSourcesRoot)\System\__ComObject.cs" />
<SystemSources Condition="'$(FeatureCominterop)' == 'true'" Include="$(BclSourcesRoot)\System\Variant.cs" />
<SystemSources Condition="'$(FeatureClassicCominterop)' == 'true'" Include="$(BclSourcesRoot)\System\OleAutBinder.cs" />
+ <SystemSources Condition="'$(FeatureSpanOfT)' == 'true'" Include="$(BclSourcesRoot)\System\ByReference.cs" />
<SystemSources Condition="'$(FeatureSpanOfT)' == 'true'" Include="$(BclSourcesRoot)\System\Span.cs" />
<SystemSources Condition="'$(FeatureSpanOfT)' == 'true'" Include="$(BclSourcesRoot)\System\ReadOnlySpan.cs" />
</ItemGroup>
diff --git a/src/mscorlib/src/System/ByReference.cs b/src/mscorlib/src/System/ByReference.cs
new file mode 100644
index 0000000000..6f8bb2281e
--- /dev/null
+++ b/src/mscorlib/src/System/ByReference.cs
@@ -0,0 +1,31 @@
+// 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.CompilerServices;
+
+namespace System
+{
+ // ByReference<T> is meant to be used to represent "ref T" fields. It is working
+ // around lack of first class support for byref fields in C# and IL. The JIT and
+ // type loader has special handling for it that turns it into a thin wrapper around ref T.
+ internal struct ByReference<T>
+ {
+ private IntPtr _value;
+
+ public ByReference(ref T value)
+ {
+ // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
+ unsafe { _value = (IntPtr)Unsafe.AsPointer(ref value); }
+ }
+
+ public ref T Value
+ {
+ get
+ {
+ // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
+ unsafe { return ref Unsafe.As<IntPtr, T>(ref *(IntPtr*)_value); }
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/ReadOnlySpan.cs b/src/mscorlib/src/System/ReadOnlySpan.cs
index e94d3534fc..9235fcfa74 100644
--- a/src/mscorlib/src/System/ReadOnlySpan.cs
+++ b/src/mscorlib/src/System/ReadOnlySpan.cs
@@ -13,10 +13,10 @@ namespace System
/// characteristics on par with T[]. Unlike arrays, it can point to either managed
/// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
/// </summary>
- public unsafe struct ReadOnlySpan<T>
+ public struct ReadOnlySpan<T>
{
- /// <summary>A byref or a native ptr. Do not access directly</summary>
- private readonly IntPtr _rawPointer;
+ /// <summary>A byref or a native ptr.</summary>
+ private readonly ByReference<T> _pointer;
/// <summary>The number of elements this ReadOnlySpan contains.</summary>
private readonly int _length;
@@ -31,8 +31,7 @@ namespace System
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<T>(ref JitHelpers.GetArrayData(array));
_length = array.Length;
}
@@ -54,8 +53,7 @@ namespace System
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<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
_length = array.Length - start;
}
@@ -78,8 +76,7 @@ namespace System
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<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
_length = length;
}
@@ -105,7 +102,7 @@ namespace System
if (length < 0)
ThrowHelper.ThrowArgumentOutOfRangeException();
- _rawPointer = (IntPtr)pointer;
+ _pointer = new ByReference<T>(ref Unsafe.AsRef<T>(pointer));
_length = length;
}
@@ -114,18 +111,17 @@ namespace System
/// </summary>
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<T>(ref ptr);
_length = length;
}
/// <summary>
- /// 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.
/// </summary>
- internal unsafe ref T GetRawPointer()
+ public ref T DangerousGetPinnableReference()
{
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- return ref Unsafe.As<IntPtr, T>(ref *(IntPtr *)_rawPointer);
+ return ref _pointer.Value;
}
/// <summary>
@@ -133,7 +129,7 @@ namespace System
/// </summary>
public static implicit operator ReadOnlySpan<T>(Span<T> slice)
{
- return new ReadOnlySpan<T>(ref slice.GetRawPointer(), slice.Length);
+ return new ReadOnlySpan<T>(ref slice.DangerousGetPinnableReference(), slice.Length);
}
/// <summary>
@@ -189,7 +185,7 @@ namespace System
if ((uint)index >= (uint)_length)
ThrowHelper.ThrowIndexOutOfRangeException();
- return Unsafe.Add(ref GetRawPointer(), index);
+ return Unsafe.Add(ref DangerousGetPinnableReference(), index);
}
}
@@ -204,7 +200,7 @@ namespace System
return Array.Empty<T>();
var destination = new T[_length];
- SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref GetRawPointer(), _length);
+ SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref DangerousGetPinnableReference(), _length);
return destination;
}
@@ -221,7 +217,7 @@ namespace System
if ((uint)start > (uint)_length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new ReadOnlySpan<T>(ref Unsafe.Add(ref GetRawPointer(), start), _length - start);
+ return new ReadOnlySpan<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), _length - start);
}
/// <summary>
@@ -238,7 +234,7 @@ namespace System
if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new ReadOnlySpan<T>(ref Unsafe.Add(ref GetRawPointer(), start), length);
+ return new ReadOnlySpan<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), length);
}
/// <summary>
@@ -248,7 +244,7 @@ namespace System
public bool Equals(ReadOnlySpan<T> other)
{
return (_length == other.Length) &&
- (_length == 0 || Unsafe.AreSame(ref GetRawPointer(), ref other.GetRawPointer()));
+ (_length == 0 || Unsafe.AreSame(ref DangerousGetPinnableReference(), ref other.DangerousGetPinnableReference()));
}
/// <summary>
@@ -261,7 +257,7 @@ namespace System
if ((uint)_length > (uint)destination.Length)
return false;
- SpanHelper.CopyTo<T>(ref destination.GetRawPointer(), ref GetRawPointer(), _length);
+ SpanHelper.CopyTo<T>(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 70d8ec079a..db3b2f28b7 100644
--- a/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs
+++ b/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs
@@ -23,7 +23,7 @@ namespace System.Runtime.CompilerServices
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void* AsPointer<T>(ref T value)
{
- // The body of this function will be replaced by the EE with unsafe code that just returns sizeof !!T
+ // The body of this function will be replaced by the EE with unsafe code!!!
// See getILIntrinsicImplementationForUnsafe for how this happens.
throw new InvalidOperationException();
}
@@ -41,13 +41,25 @@ namespace System.Runtime.CompilerServices
}
/// <summary>
+ /// Reinterprets the given location as a reference to a value of type<typeparamref name="T"/>.
+ /// </summary>
+ [NonVersionable]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T AsRef<T>(void * source)
+ {
+ // The body of this function will be replaced by the EE with unsafe code!!!
+ // See getILIntrinsicImplementationForUnsafe 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
+ // The body of this function will be replaced by the EE with unsafe code!!!
// See getILIntrinsicImplementationForUnsafe for how this happens.
throw new InvalidOperationException();
}
diff --git a/src/mscorlib/src/System/Span.cs b/src/mscorlib/src/System/Span.cs
index 2eff6ae800..21785cd865 100644
--- a/src/mscorlib/src/System/Span.cs
+++ b/src/mscorlib/src/System/Span.cs
@@ -13,10 +13,10 @@ namespace System
/// characteristics on par with T[]. Unlike arrays, it can point to either managed
/// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
/// </summary>
- public unsafe struct Span<T>
+ public struct Span<T>
{
- /// <summary>A byref or a native ptr. Do not access directly</summary>
- private readonly IntPtr _rawPointer;
+ /// <summary>A byref or a native ptr.</summary>
+ private readonly ByReference<T> _pointer;
/// <summary>The number of elements this Span contains.</summary>
private readonly int _length;
@@ -36,8 +36,7 @@ namespace System
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<T>(ref JitHelpers.GetArrayData(array));
_length = array.Length;
}
@@ -64,8 +63,7 @@ namespace System
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<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
_length = array.Length - start;
}
@@ -93,8 +91,7 @@ namespace System
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<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
_length = length;
}
@@ -120,7 +117,7 @@ namespace System
if (length < 0)
ThrowHelper.ThrowArgumentOutOfRangeException();
- _rawPointer = (IntPtr)pointer;
+ _pointer = new ByReference<T>(ref Unsafe.AsRef<T>(pointer));
_length = length;
}
@@ -129,18 +126,17 @@ namespace System
/// </summary>
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<T>(ref ptr);
_length = length;
}
/// <summary>
- /// 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.
/// </summary>
- internal unsafe ref T GetRawPointer()
+ public ref T DangerousGetPinnableReference()
{
- // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
- return ref Unsafe.As<IntPtr, T>(ref *(IntPtr*)_rawPointer);
+ return ref _pointer.Value;
}
/// <summary>
@@ -196,14 +192,14 @@ namespace System
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 @@ namespace System
return Array.Empty<T>();
var destination = new T[_length];
- SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref GetRawPointer(), _length);
+ SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref DangerousGetPinnableReference(), _length);
return destination;
}
@@ -235,7 +231,7 @@ namespace System
if ((uint)start > (uint)_length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new Span<T>(ref Unsafe.Add(ref GetRawPointer(), start), _length - start);
+ return new Span<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), _length - start);
}
/// <summary>
@@ -252,7 +248,7 @@ namespace System
if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
- return new Span<T>(ref Unsafe.Add(ref GetRawPointer(), start), length);
+ return new Span<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), length);
}
/// <summary>
@@ -262,7 +258,7 @@ namespace System
public bool Equals(Span<T> other)
{
return (_length == other.Length) &&
- (_length == 0 || Unsafe.AreSame(ref GetRawPointer(), ref other.GetRawPointer()));
+ (_length == 0 || Unsafe.AreSame(ref DangerousGetPinnableReference(), ref other.DangerousGetPinnableReference()));
}
/// <summary>
@@ -275,7 +271,7 @@ namespace System
if ((uint)_length > (uint)destination.Length)
return false;
- SpanHelper.CopyTo<T>(ref destination.GetRawPointer(), ref GetRawPointer(), _length);
+ SpanHelper.CopyTo<T>(ref destination.DangerousGetPinnableReference(), ref DangerousGetPinnableReference(), _length);
return true;
}
@@ -287,7 +283,7 @@ namespace System
if ((uint)values.Length > (uint)_length)
ThrowHelper.ThrowArgumentOutOfRangeException();
- SpanHelper.CopyTo<T>(ref GetRawPointer(), ref values.GetRawPointer(), values.Length);
+ SpanHelper.CopyTo<T>(ref DangerousGetPinnableReference(), ref values.DangerousGetPinnableReference(), values.Length);
}
}
@@ -308,7 +304,7 @@ namespace System
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
return new Span<byte>(
- ref Unsafe.As<T, byte>(ref source.GetRawPointer()),
+ ref Unsafe.As<T, byte>(ref source.DangerousGetPinnableReference()),
checked(source.Length * Unsafe.SizeOf<T>()));
}
@@ -327,7 +323,7 @@ namespace System
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
return new ReadOnlySpan<byte>(
- ref Unsafe.As<T, byte>(ref source.GetRawPointer()),
+ ref Unsafe.As<T, byte>(ref source.DangerousGetPinnableReference()),
checked(source.Length * Unsafe.SizeOf<T>()));
}
@@ -342,7 +338,7 @@ namespace System
/// <exception cref="System.ArgumentException">
/// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
/// </exception>
- public static unsafe Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source)
+ public static Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source)
where TFrom : struct
where TTo : struct
{
@@ -352,7 +348,7 @@ namespace System
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
return new Span<TTo>(
- ref Unsafe.As<TFrom, TTo>(ref source.GetRawPointer()),
+ ref Unsafe.As<TFrom, TTo>(ref source.DangerousGetPinnableReference()),
checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
}
@@ -367,7 +363,7 @@ namespace System
/// <exception cref="System.ArgumentException">
/// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
/// </exception>
- public static unsafe ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source)
+ public static ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source)
where TFrom : struct
where TTo : struct
{
@@ -377,7 +373,7 @@ namespace System
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
return new ReadOnlySpan<TTo>(
- ref Unsafe.As<TFrom, TTo>(ref source.GetRawPointer()),
+ ref Unsafe.As<TFrom, TTo>(ref source.DangerousGetPinnableReference()),
checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
}
}
diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp
index 0ee260e3ef..b7fc67cd24 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 ec5486ac7a..47f1fecdec 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 fac4cb44f2..cebd410347 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,9 @@ unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
}
else
{
+ // TODO-SPAN: Proper GC reporting
+ memset(gcPtrs, TYPE_GC_NONE,
+ (VMClsHnd.GetSize() + sizeof(void*) -1)/ sizeof(void*));
result = 0;
}
}
@@ -7034,7 +7033,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 ab55f11ced..682268eb39 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 1e40ea996c..1cf71499e6 100644
--- a/src/vm/methodtablebuilder.h
+++ b/src/vm/methodtablebuilder.h
@@ -2081,6 +2081,7 @@ private:
DWORD NumGCPointerSeries;
DWORD NumInstanceFieldBytes;
+ bool fIsByRefLikeType;
bool fHasFixedAddressValueTypes;
bool fHasSelfReferencingStaticValueTypeField_WithRVA;
diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h
index c145e4deff..7a0b1a04f1 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 8d19a5c20e..626ca3c9d3 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 712543c2b1..62d6656eaf 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);