Consume Roslyn with `ref` fields support (#71498)
authorAaron Robinson <arobins@microsoft.com>
Sat, 2 Jul 2022 21:07:27 +0000 (14:07 -0700)
committerGitHub <noreply@github.com>
Sat, 2 Jul 2022 21:07:27 +0000 (14:07 -0700)
* Use C# ref field support
Update public APIs

* Create new ByReference to be used in Reflection and tailcall slow paths

* Limit net6.0 TFM in DiagnosticsSource to C# 10.

* Remove temporary LifetimeAnnotationAttribute
This is supplied by Roslyn.

* Update to Roslyn compiler with ref field support.

* Update comments with those approved in official docs.

* Handle byref field in interpreter

* Fix build break when DEBUG_INTERP defined.

60 files changed:
eng/Versions.props
src/coreclr/System.Private.CoreLib/src/System/TypedReference.CoreCLR.cs
src/coreclr/inc/dacvars.h
src/coreclr/jit/importer.cpp
src/coreclr/jit/namedintrinsiclist.h
src/coreclr/nativeaot/System.Private.CoreLib/src/System/TypedReference.cs
src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
src/coreclr/tools/Common/JitInterface/SystemVStructClassificator.cs
src/coreclr/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs
src/coreclr/tools/Common/TypeSystem/Common/MetadataTypeSystemContext.cs
src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.cs
src/coreclr/tools/Common/TypeSystem/Common/WellKnownType.cs
src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs
src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs
src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/IBCProfileData.cs
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/InstanceFieldLayout.cs
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Platform.cs
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILTestAssembly/InstanceFieldLayout.il
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/InstanceFieldLayoutTests.cs
src/coreclr/tools/dotnet-pgo/dotnet-pgo.csproj
src/coreclr/vm/appdomain.cpp
src/coreclr/vm/classnames.h
src/coreclr/vm/corelib.h
src/coreclr/vm/interpreter.cpp
src/coreclr/vm/interpreter.h
src/coreclr/vm/jitinterface.cpp
src/coreclr/vm/methodtable.cpp
src/coreclr/vm/methodtablebuilder.cpp
src/coreclr/vm/mlinfo.cpp
src/coreclr/vm/siginfo.cpp
src/coreclr/vm/tailcallhelp.cpp
src/coreclr/vm/vars.cpp
src/coreclr/vm/vars.hpp
src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj
src/libraries/System.Memory/ref/System.Memory.cs
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
src/libraries/System.Private.CoreLib/src/System/ByReference.cs
src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs
src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanFormat.cs
src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs
src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs
src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/LifetimeAnnotationAttribute.cs [deleted file]
src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs
src/libraries/System.Private.CoreLib/src/System/Span.cs
src/libraries/System.Private.CoreLib/src/System/String.cs
src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs
src/libraries/System.Private.CoreLib/src/System/TypedReference.cs
src/libraries/System.Runtime.Serialization.Formatters/tests/FormatterServicesTests.cs
src/libraries/System.Runtime/ref/System.Runtime.cs
src/mono/System.Private.CoreLib/src/System/TypedReference.Mono.cs
src/mono/mono/metadata/class-init.c
src/mono/mono/metadata/marshal-shared.c
src/mono/mono/mini/interp/interp.c
src/mono/mono/mini/interp/transform.c
src/mono/mono/mini/intrinsics.c

index 6586408..26772fc 100644 (file)
@@ -49,7 +49,7 @@
     <!--
       TODO: Remove pinned version once arcade supplies a compiler that enables the repo to compile.
     -->
-    <MicrosoftNetCompilersToolsetVersion>4.4.0-1.22315.13</MicrosoftNetCompilersToolsetVersion>
+    <MicrosoftNetCompilersToolsetVersion>4.4.0-1.22328.22</MicrosoftNetCompilersToolsetVersion>
     <!-- SDK dependencies -->
     <MicrosoftDotNetCompatibilityVersion>2.0.0-preview.4.22252.4</MicrosoftDotNetCompatibilityVersion>
     <!-- Arcade dependencies -->
index 6e44ec1..dc7e3ee 100644 (file)
@@ -12,7 +12,7 @@ namespace System
     [System.Runtime.Versioning.NonVersionable] // This only applies to field layout
     public ref partial struct TypedReference
     {
-        private readonly ByReference<byte> _value;
+        private readonly ref byte _value;
         private readonly IntPtr _type;
 
         public static unsafe object? ToObject(TypedReference value)
@@ -38,11 +38,11 @@ namespace System
 
             if (pMethodTable->IsValueType)
             {
-                result = RuntimeHelpers.Box(pMethodTable, ref value._value.Value);
+                result = RuntimeHelpers.Box(pMethodTable, ref value._value);
             }
             else
             {
-                result = Unsafe.As<byte, object>(ref value._value.Value);
+                result = Unsafe.As<byte, object>(ref value._value);
             }
 
             return result;
index 68ec3af..5ce6683 100644 (file)
@@ -163,7 +163,6 @@ DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pStringClass, ::g_pStringClass)
 DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pArrayClass, ::g_pArrayClass)
 DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pSZArrayHelperClass, ::g_pSZArrayHelperClass)
 DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pNullableClass, ::g_pNullableClass)
-DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pByReferenceClass, ::g_pByReferenceClass)
 DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pExceptionClass, ::g_pExceptionClass)
 DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pThreadAbortExceptionClass, ::g_pThreadAbortExceptionClass)
 DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pOutOfMemoryExceptionClass, ::g_pOutOfMemoryExceptionClass)
index 3caad07..f01b80f 100644 (file)
@@ -3791,8 +3791,6 @@ GenTree* Compiler::impIntrinsic(GenTree*                newobjThis,
             break;
 
         case NI_Internal_Runtime_MethodTable_Of:
-        case NI_System_ByReference_ctor:
-        case NI_System_ByReference_get_Value:
         case NI_System_Activator_AllocatorOf:
         case NI_System_Activator_DefaultConstructorOf:
         case NI_System_EETypePtr_EETypePtrOf:
@@ -3899,35 +3897,6 @@ GenTree* Compiler::impIntrinsic(GenTree*                newobjThis,
                 break;
             }
 
-            // Implement ByReference Ctor.  This wraps the assignment of the ref into a byref-like field
-            // in a value type.  The canonical example of this is Span<T>. In effect this is just a
-            // substitution.  The parameter byref will be assigned into the newly allocated object.
-            case NI_System_ByReference_ctor:
-            {
-                // Remove call to constructor and directly assign the byref passed
-                // to the call to the first slot of the ByReference struct.
-                GenTree*             op1               = impPopStack().val;
-                GenTree*             thisptr           = newobjThis;
-                CORINFO_FIELD_HANDLE fldHnd            = info.compCompHnd->getFieldInClass(clsHnd, 0);
-                GenTree*             field             = gtNewFieldRef(TYP_BYREF, fldHnd, thisptr, 0);
-                GenTree*             assign            = gtNewAssignNode(field, op1);
-                GenTree*             byReferenceStruct = gtCloneExpr(thisptr->gtGetOp1());
-                assert(byReferenceStruct != nullptr);
-                impPushOnStack(byReferenceStruct, typeInfo(TI_STRUCT, clsHnd));
-                retNode = assign;
-                break;
-            }
-
-            // Implement ptr value getter for ByReference struct.
-            case NI_System_ByReference_get_Value:
-            {
-                GenTree*             op1    = impPopStack().val;
-                CORINFO_FIELD_HANDLE fldHnd = info.compCompHnd->getFieldInClass(clsHnd, 0);
-                GenTree*             field  = gtNewFieldRef(TYP_BYREF, fldHnd, op1, 0);
-                retNode                     = field;
-                break;
-            }
-
             case NI_System_Runtime_CompilerServices_RuntimeHelpers_CreateSpan:
             {
                 retNode = impCreateSpanIntrinsic(sig);
@@ -5549,17 +5518,6 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
                 result = NI_System_Activator_DefaultConstructorOf;
             }
         }
-        else if (strcmp(className, "ByReference`1") == 0)
-        {
-            if (strcmp(methodName, ".ctor") == 0)
-            {
-                result = NI_System_ByReference_ctor;
-            }
-            else if (strcmp(methodName, "get_Value") == 0)
-            {
-                result = NI_System_ByReference_get_Value;
-            }
-        }
         else if (strcmp(className, "Math") == 0 || strcmp(className, "MathF") == 0)
         {
             if (strcmp(methodName, "Abs") == 0)
index c206a8c..ca812ab 100644 (file)
@@ -76,8 +76,6 @@ enum NamedIntrinsic : unsigned short
     NI_Array_Get,
     NI_Array_Set,
 
-    NI_System_ByReference_ctor,
-    NI_System_ByReference_get_Value,
     NI_System_Activator_AllocatorOf,
     NI_System_Activator_DefaultConstructorOf,
     NI_System_EETypePtr_EETypePtrOf,
index cb08788..5385e5e 100644 (file)
@@ -16,12 +16,12 @@ namespace System
     public ref struct TypedReference
     {
         // Do not change the ordering of these fields. The JIT has a dependency on this layout.
-        private readonly ByReference<byte> _value;
+        private readonly ref byte _value;
         private readonly RuntimeTypeHandle _typeHandle;
 
         private TypedReference(object target, int offset, RuntimeTypeHandle typeHandle)
         {
-            _value = new ByReference<byte>(ref Unsafe.Add<byte>(ref target.GetRawData(), offset));
+            _value = ref Unsafe.Add<byte>(ref target.GetRawData(), offset);
             _typeHandle = typeHandle;
         }
 
@@ -81,7 +81,7 @@ namespace System
             [MethodImpl(MethodImplOptions.AggressiveInlining)]
             get
             {
-                return ref _value.Value;
+                return ref _value;
             }
         }
     }
index fca3a10..486ef40 100644 (file)
@@ -2330,11 +2330,6 @@ namespace Internal.JitInterface
         {
             int result = 0;
 
-            if (type.IsByReferenceOfT)
-            {
-                return MarkGcField(gcPtrs, CorInfoGCType.TYPE_GC_BYREF);
-            }
-
             foreach (var field in type.GetFields())
             {
                 if (field.IsStatic)
@@ -2952,15 +2947,6 @@ namespace Internal.JitInterface
                 type = asCorInfoType(fieldType);
             }
 
-            Debug.Assert(!fieldDesc.OwningType.IsByReferenceOfT ||
-                fieldDesc.OwningType.GetKnownField("_value").FieldType.Category == TypeFlags.IntPtr);
-            if (type == CorInfoType.CORINFO_TYPE_NATIVEINT && fieldDesc.OwningType.IsByReferenceOfT)
-            {
-                Debug.Assert(structType == null || *structType == null);
-                Debug.Assert(fieldDesc.Offset.AsInt == 0);
-                type = CorInfoType.CORINFO_TYPE_BYREF;
-            }
-
             return type;
         }
 
index 0c331f9..1237cdb 100644 (file)
@@ -295,21 +295,7 @@ namespace Internal.JitInterface
                     return false;
                 }
 
-                SystemVClassificationType fieldClassificationType;
-                if (typeDesc.IsByReferenceOfT)
-                {
-                    // ByReference<T> is a special type whose single IntPtr field holds a by-ref potentially interior pointer to GC
-                    // memory, so classify its field as such
-                    Debug.Assert(numIntroducedFields == 1);
-                    Debug.Assert(field.FieldType.IsWellKnownType(WellKnownType.IntPtr));
-
-                    fieldClassificationType = SystemVClassificationTypeIntegerByRef;
-                }
-                else
-                {
-                    fieldClassificationType = TypeDef2SystemVClassification(field.FieldType);
-                }
-
+                SystemVClassificationType fieldClassificationType = TypeDef2SystemVClassification(field.FieldType);
                 if (fieldClassificationType == SystemVClassificationTypeStruct)
                 {
                     bool inEmbeddedStructPrev = helper.InEmbeddedStruct;
index 838dd70..cb4755c 100644 (file)
@@ -157,7 +157,7 @@ namespace Internal.TypeSystem
                     {
                         SetFieldLayout(refMap, offset, _pointerSize, FieldLayoutTag.ORef);
                     }
-                    else if (field.FieldType.IsByRef || field.FieldType.IsByReferenceOfT)
+                    else if (field.FieldType.IsByRef)
                     {
                         SetFieldLayout(refMap, offset, _pointerSize, FieldLayoutTag.ByRef);
                     }
index b65e813..97b6e62 100644 (file)
@@ -43,7 +43,6 @@ namespace Internal.TypeSystem
             "Exception",
 
             "TypedReference",
-            "ByReference`1",
         };
 
         public static IEnumerable<string> WellKnownTypeNames => s_wellKnownTypeNames;
@@ -71,7 +70,7 @@ namespace Internal.TypeSystem
             // Initialize all well known types - it will save us from checking the name for each loaded type
             for (int typeIndex = 0; typeIndex < _wellKnownTypes.Length; typeIndex++)
             {
-                // Require System.Object to be present as a minimal sanity check. 
+                // Require System.Object to be present as a minimal sanity check.
                 // The set of required well-known types is not strictly defined since different .NET profiles implement different subsets.
                 MetadataType type = systemModule.GetType("System", s_wellKnownTypeNames[typeIndex], throwIfNotFound: typeIndex == (int)WellKnownType.Object);
                 if (type != null)
@@ -88,7 +87,7 @@ namespace Internal.TypeSystem
 
             int typeIndex = (int)wellKnownType - 1;
             DefType type = _wellKnownTypes[typeIndex];
-            if (type == null && throwIfNotFound) 
+            if (type == null && throwIfNotFound)
                 ThrowHelper.ThrowTypeLoadException("System", s_wellKnownTypeNames[typeIndex], SystemModule);
 
             return type;
index 160dac0..d9d2907 100644 (file)
@@ -117,7 +117,6 @@ namespace Internal.TypeSystem
                 case WellKnownType.RuntimeMethodHandle:
                 case WellKnownType.RuntimeFieldHandle:
                 case WellKnownType.TypedReference:
-                case WellKnownType.ByReferenceOfT:
                     flags = TypeFlags.ValueType;
                     break;
 
@@ -307,18 +306,6 @@ namespace Internal.TypeSystem
         }
 
         /// <summary>
-        /// Gets a value indicating whether this is a generic definition, or
-        /// an instance of System.ByReference`1.
-        /// </summary>
-        public bool IsByReferenceOfT
-        {
-            get
-            {
-                return this.GetTypeDefinition().IsWellKnownType(WellKnownType.ByReferenceOfT);
-            }
-        }
-
-        /// <summary>
         /// Gets a value indicating whether this is an array type (<see cref="ArrayType"/>).
         /// Note this will return true for both multidimensional array types and vector types.
         /// Use <see cref="IsSzArray"/> to check for vector types.
index cc3e563..b16257f 100644 (file)
@@ -46,6 +46,5 @@ namespace Internal.TypeSystem
         Exception,
 
         TypedReference,
-        ByReferenceOfT,
     }
 }
index 4c11c05..01b82b8 100644 (file)
@@ -411,7 +411,6 @@ namespace Internal.TypeSystem.Interop
                 bool isBlittable = MarshalUtils.IsBlittableType(type);
 
                 // Blittable generics are allowed to be marshalled with the following exceptions:
-                // * ByReference<T>: This represents an interior pointer and is not actually blittable
                 // * Nullable<T>: We don't want to be locked into the default behavior as we may want special handling later
                 // * Vector64<T>: Represents the __m64 ABI primitive which requires currently unimplemented handling
                 // * Vector128<T>: Represents the __m128 ABI primitive which requires currently unimplemented handling
@@ -420,7 +419,6 @@ namespace Internal.TypeSystem.Interop
                 // We can't block these types for field scenarios for back-compat reasons.
 
                 if (type.HasInstantiation && !isField && (!isBlittable
-                    || InteropTypes.IsSystemByReference(context, type)
                     || InteropTypes.IsSystemSpan(context, type)
                     || InteropTypes.IsSystemReadOnlySpan(context, type)
                     || InteropTypes.IsSystemNullable(context, type)
index d78b275..f69879a 100644 (file)
@@ -117,11 +117,6 @@ namespace Internal.TypeSystem.Interop
             return IsCoreNamedType(context, type, "System", "ArgIterator");
         }
 
-        public static bool IsSystemByReference(TypeSystemContext context, TypeDesc type)
-        {
-            return IsCoreNamedType(context, type, "System", "ByReference`1");
-        }
-
         public static bool IsSystemSpan(TypeSystemContext context, TypeDesc type)
         {
             return IsCoreNamedType(context, type, "System", "Span`1");
index 0f4dded..acaa1a0 100644 (file)
@@ -372,11 +372,6 @@ namespace Internal.IL
                     return;
                 }
 
-                if (method.OwningType.IsByReferenceOfT && (method.IsConstructor || method.Name == "get_Value"))
-                {
-                    return;
-                }
-
                 if (IsEETypePtrOf(method))
                 {
                     if (runtimeDeterminedMethod.IsRuntimeDeterminedExactMethod)
index ad294d7..3963a30 100644 (file)
@@ -7,15 +7,15 @@ using System.Diagnostics;
 
 using Internal.TypeSystem;
 
-// The GCRef map is used to encode GC type of arguments for callsites. Logically, it is sequence <pos, token> where pos is 
+// The GCRef map is used to encode GC type of arguments for callsites. Logically, it is sequence <pos, token> where pos is
 // position of the reference in the stack frame and token is type of GC reference (one of GCREFMAP_XXX values).
 //
-// - The encoding always starts at the byte boundary. The high order bit of each byte is used to signal end of the encoding 
+// - The encoding always starts at the byte boundary. The high order bit of each byte is used to signal end of the encoding
 // stream. The last byte has the high order bit zero. It means that there are 7 useful bits in each byte.
 // - "pos" is always encoded as delta from previous pos.
-// - The basic encoding unit is two bits. Values 0, 1 and 2 are the common constructs (skip single slot, GC reference, interior 
-// pointer). Value 3 means that extended encoding follows. 
-// - The extended information is integer encoded in one or more four bit blocks. The high order bit of the four bit block is 
+// - The basic encoding unit is two bits. Values 0, 1 and 2 are the common constructs (skip single slot, GC reference, interior
+// pointer). Value 3 means that extended encoding follows.
+// - The extended information is integer encoded in one or more four bit blocks. The high order bit of the four bit block is
 // used to signal the end.
 // - For x86, the encoding starts by size of the callee poped stack. The size is encoded using the same mechanism as above (two bit
 // basic encoding, with extended encoding for large values).
@@ -35,7 +35,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
         private int _pendingByte;
 
         /// <summary>
-        /// Number of bits in pending byte. Note that the trailing zero bits are not written out, 
+        /// Number of bits in pending byte. Note that the trailing zero bits are not written out,
         /// so this can be more than 7.
         /// </summary>
         private int _bits;
@@ -293,7 +293,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
 
         private void FindByRefPointerOffsetsInByRefLikeObject(TypeDesc type, ArgDestination argDest, int delta, CORCOMPILE_GCREFMAP_TOKENS[] frame)
         {
-            if (type.IsByReferenceOfT || type.IsByRef)
+            if (type.IsByRef)
             {
                 argDest.GcMark(frame, delta, interior: true);
                 return;
index f507cab..6272592 100644 (file)
@@ -253,7 +253,7 @@ namespace ILCompiler
                     size = fieldType.GetElementSize().AsInt;
                     alignment = size;
                 }
-                else if (fieldType.IsByRef || fieldType.IsByRefLike || fieldType.IsByReferenceOfT)
+                else if (fieldType.IsByRef || fieldType.IsByRefLike)
                 {
                     ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, fieldDesc.OwningType);
                 }
index 266be87..a36d77e 100644 (file)
@@ -18,13 +18,13 @@ namespace ILCompiler.IBC
         public override string ToString()
         {
             return
-                $"""
-                FormatVersion: {FormatVersion}
-                Runtime:       {Runtime}
-                Os:            {Os}
-                Arch:          {Arch}
+$@"
+FormatVersion: {FormatVersion}
+Runtime:       {Runtime}
+Os:            {Os}
+Arch:          {Arch}
 
-                """;
+";
         }
 
         public static MibcConfig FromKeyValueMap(Dictionary<string, string> kvMap)
index 656d075..b49dd4f 100644 (file)
@@ -296,7 +296,7 @@ namespace IsByRefLike
 {
     public ref struct ByRefLikeStruct
     {
-        ByReference<object> ByRef;
+        ref object ByRef;
     }
 
     public struct NotByRefLike
index ac8b380..886f7aa 100644 (file)
@@ -48,7 +48,7 @@ namespace System
     public abstract class ValueType { }
     public abstract class Enum : ValueType { }
     public struct Nullable<T> where T : struct { }
-    
+
     public sealed class String { }
     public abstract class Array : System.Collections.IList { }
     public abstract class Delegate { }
@@ -68,11 +68,9 @@ namespace System
 
     public ref struct TypedReference
     {
-        private readonly ByReference<byte> _value;
+        private readonly ref byte _value;
         private readonly RuntimeTypeHandle _typeHandle;
     }
-
-    public ref struct ByReference<T> { }
 }
 
 namespace System.Collections
index 8390664..35bf1dd 100644 (file)
@@ -4,18 +4,18 @@
 .class public sequential ansi sealed beforefieldinit IsByRefLike.InvalidStruct
        extends [CoreTestAssembly]System.ValueType
 {
-  .field private valuetype [CoreTestAssembly]System.ByReference`1<object> ByRef
+  .field private object& ByRef
 }
 
 .class public auto ansi beforefieldinit IsByRefLike.InvalidClass1
        extends [CoreTestAssembly]System.Object
 {
-  .field private valuetype [CoreTestAssembly]System.ByReference`1<object> ByRef
+  .field private object& ByRef
 }
 
 .class public auto ansi beforefieldinit IsByRefLike.InvalidClass2
        extends [CoreTestAssembly]System.Object
 {
-  .custom instance void [CoreTestAssembly]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( 01 00 00 00 ) 
-  .field private valuetype [CoreTestAssembly]System.ByReference`1<object> ByRef
+  .custom instance void [CoreTestAssembly]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( 01 00 00 00 )
+  .field private object& ByRef
 }
index e92749b..0a60a72 100644 (file)
@@ -31,7 +31,7 @@ namespace TypeSystemTests
             MetadataType t = _testModule.GetType("Explicit", "Class1");
 
             // With 64bit, there should be 8 bytes for the System.Object EE data pointer +
-            // 10 bytes up until the offset of the char field + the char size of 2 + we 
+            // 10 bytes up until the offset of the char field + the char size of 2 + we
             // round up the whole instance size to the next pointer size (+4) = 24
             Assert.Equal(24, t.InstanceByteCount.AsInt);
 
@@ -95,7 +95,7 @@ namespace TypeSystemTests
 
                 if (f.Name == "Lol")
                 {
-                    // First field after base class, with offset 0 so it should lie on the byte count of 
+                    // First field after base class, with offset 0 so it should lie on the byte count of
                     // the base class = 20
                     Assert.Equal(20, f.Offset.AsInt);
                 }
@@ -822,11 +822,6 @@ namespace TypeSystemTests
             }
 
             {
-                DefType type = _context.GetWellKnownType(WellKnownType.ByReferenceOfT);
-                Assert.True(type.IsByRefLike);
-            }
-
-            {
                 DefType type = _testModule.GetType("IsByRefLike", "ByRefLikeStruct");
                 Assert.True(type.IsByRefLike);
             }
index 14a99e9..ab5cc92 100644 (file)
@@ -21,6 +21,9 @@
     <PackageReleaseNotes>$(Description)</PackageReleaseNotes>
     <RootNamespace>Microsoft.Diagnostics.Tools.Pgo</RootNamespace>
     <RollForward>Major</RollForward>
+    <!-- TODO Remove the language version limitation when the reference assemblies
+        are updated with the new scoped keyword. -->
+    <LangVersion>10</LangVersion>
   </PropertyGroup>
 
   <ItemGroup>
index d679c69..6b80b79 100644 (file)
@@ -1362,12 +1362,6 @@ void SystemDomain::LoadBaseSystemClasses()
     // the SZArrayHelper class here.
     g_pSZArrayHelperClass = CoreLibBinder::GetClass(CLASS__SZARRAYHELPER);
 
-    // Load ByReference class
-    //
-    // NOTE: ByReference<T> must be the first by-ref-like system type to be loaded,
-    //       because MethodTable::ClassifyEightBytesWithManagedLayout depends on it.
-    g_pByReferenceClass = CoreLibBinder::GetClass(CLASS__BYREFERENCE);
-
     // Load Nullable class
     g_pNullableClass = CoreLibBinder::GetClass(CLASS__NULLABLE);
 
index dee85ad..9a4d4e3 100644 (file)
@@ -15,7 +15,6 @@
 #define g_ArrayClassName "System.Array"
 
 #define g_NullableName "Nullable`1"
-#define g_ByReferenceName "ByReference`1"
 
 #define g_CollectionsEnumerableItfName "System.Collections.IEnumerable"
 #define g_CollectionsEnumeratorClassName "System.Collections.IEnumerator"
index cd4995a..cd9b127 100644 (file)
@@ -575,9 +575,9 @@ DEFINE_FIELD(NULL,                  VALUE,          Value)
 
 DEFINE_CLASS(NULLABLE,              System,                 Nullable`1)
 
-DEFINE_CLASS(BYREFERENCE,           System,                 ByReference`1)
+DEFINE_CLASS(BYREFERENCE,           System,                 ByReference)
 DEFINE_METHOD(BYREFERENCE,          CTOR,                   .ctor, NoSig)
-DEFINE_METHOD(BYREFERENCE,          GET_VALUE,              get_Value, NoSig)
+DEFINE_FIELD(BYREFERENCE,           VALUE,                  Value)
 DEFINE_CLASS(SPAN,                  System,                 Span`1)
 DEFINE_METHOD(SPAN,                 CTOR_PTR_INT,           .ctor, IM_VoidPtr_Int_RetVoid)
 DEFINE_METHOD(SPAN,                 GET_ITEM,               get_Item, IM_Int_RetRefT)
index 0200c71..5e6d3e9 100644 (file)
@@ -9177,14 +9177,6 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
     {
         switch (intrinsicId)
         {
-        case NI_System_ByReference_ctor:
-            DoByReferenceCtor();
-            didIntrinsic = true;
-            break;
-        case NI_System_ByReference_get_Value:
-            DoByReferenceValue();
-            didIntrinsic = true;
-            break;
 #if INTERP_ILSTUBS
         case NI_System_StubHelpers_GetStubContext:
             OpStackSet<void*>(m_curStackHt, GetStubContext());
@@ -10752,74 +10744,6 @@ void Interpreter::DoGetTypeFromHandle()
     OpStackTypeSet(ind, InterpreterType(CORINFO_TYPE_CLASS));
 }
 
-void Interpreter::DoByReferenceCtor()
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_COOPERATIVE;
-    } CONTRACTL_END;
-
-    // Note 'this' is not passed on the operand stack...
-    _ASSERTE(m_curStackHt > 0);
-    _ASSERTE(m_callThisArg != NULL);
-    unsigned valInd = m_curStackHt - 1;
-    CorInfoType valCit = OpStackTypeGet(valInd).ToCorInfoType();
-
-#ifdef _DEBUG
-    if (valCit != CORINFO_TYPE_BYREF)
-    {
-        VerificationError("ByReference<T>.ctor called with non-byref value.");
-    }
-#endif // _DEBUG
-
-#if INTERP_TRACING
-    if (s_TraceInterpreterILFlag.val(CLRConfig::INTERNAL_TraceInterpreterIL))
-    {
-        fprintf(GetLogFile(), "    ByReference<T>.ctor -- intrinsic\n");
-    }
-#endif // INTERP_TRACING
-
-    GCX_FORBID();
-    void** thisPtr = reinterpret_cast<void**>(m_callThisArg);
-    void* val = OpStackGet<void*>(valInd);
-    *thisPtr = val;
-    m_curStackHt--;
-}
-
-void Interpreter::DoByReferenceValue()
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_COOPERATIVE;
-    } CONTRACTL_END;
-
-    _ASSERTE(m_curStackHt > 0);
-    unsigned slot = m_curStackHt - 1;
-    CorInfoType thisCit = OpStackTypeGet(slot).ToCorInfoType();
-
-#ifdef _DEBUG
-    if (thisCit != CORINFO_TYPE_BYREF)
-    {
-        VerificationError("ByReference<T>.get_Value called with non-byref this");
-    }
-#endif // _DEBUG
-
-#if INTERP_TRACING
-    if (s_TraceInterpreterILFlag.val(CLRConfig::INTERNAL_TraceInterpreterIL))
-    {
-        fprintf(GetLogFile(), "    ByReference<T>.getValue -- intrinsic\n");
-    }
-#endif // INTERP_TRACING
-
-    GCX_FORBID();
-    void** thisPtr = OpStackGet<void**>(slot);
-    void* value = *thisPtr;
-    OpStackSet<void*>(slot, value);
-    OpStackTypeSet(slot, InterpreterType(CORINFO_TYPE_BYREF));
-}
-
 void Interpreter::DoSIMDHwAccelerated()
 {
     CONTRACTL {
index 7856f97..517cb55 100644 (file)
@@ -1774,8 +1774,6 @@ private:
     void DoStringLength();
     void DoStringGetChar();
     void DoGetTypeFromHandle();
-    void DoByReferenceCtor();
-    void DoByReferenceValue();
     void DoSIMDHwAccelerated();
     void DoGetIsSupported();
 
index 84fbd5a..ea91727 100644 (file)
@@ -2067,9 +2067,6 @@ static unsigned ComputeGCLayout(MethodTable * pMT, BYTE* gcPtrs)
 
     _ASSERTE(pMT->IsValueType());
 
-    if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
-        return MarkGCField(gcPtrs, TYPE_GC_BYREF);
-
     unsigned result = 0;
     ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
     for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
@@ -9214,17 +9211,6 @@ CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd,
     TypeHandle clsHnd = TypeHandle();
     FieldDesc* field = (FieldDesc*) fieldHnd;
     CorElementType type   = field->GetFieldType();
-
-    if (type == ELEMENT_TYPE_I)
-    {
-        PTR_MethodTable enclosingMethodTable = field->GetApproxEnclosingMethodTable();
-        if (enclosingMethodTable->IsByRefLike() && enclosingMethodTable->HasSameTypeDefAs(g_pByReferenceClass))
-        {
-            _ASSERTE(field->GetOffset() == 0);
-            return CORINFO_TYPE_BYREF;
-        }
-    }
-
     if (!CorTypeInfo::IsPrimitiveType(type))
     {
         PCCOR_SIGNATURE sig;
index c3f40ee..98c3d6f 100644 (file)
@@ -2285,12 +2285,6 @@ bool MethodTable::ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassi
         numIntroducedFields = GetNumInstanceFieldBytes() / pFieldStart->GetSize();
     }
 
-    // System types are loaded before others, so ByReference<T> would be loaded before Span<T> or any other type that has a
-    // ByReference<T> field. ByReference<T> is the first by-ref-like system type to be loaded (see
-    // SystemDomain::LoadBaseSystemClasses), so if the current method table is marked as by-ref-like and g_pByReferenceClass is
-    // null, it must be the initial load of ByReference<T>.
-    bool isThisByReferenceOfT = IsByRefLike() && (g_pByReferenceClass == nullptr || HasSameTypeDefAs(g_pByReferenceClass));
-
     for (unsigned int fieldIndex = 0; fieldIndex < numIntroducedFields; fieldIndex++)
     {
         FieldDesc* pField;
@@ -2320,20 +2314,7 @@ bool MethodTable::ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassi
         }
 
         CorElementType fieldType = pField->GetFieldType();
-
-        SystemVClassificationType fieldClassificationType;
-        if (isThisByReferenceOfT)
-        {
-            // ByReference<T> is a special type whose single IntPtr field holds a by-ref potentially interior pointer to GC
-            // memory, so classify its field as such
-            _ASSERTE(numIntroducedFields == 1);
-            _ASSERTE(fieldType == CorElementType::ELEMENT_TYPE_I);
-            fieldClassificationType = SystemVClassificationTypeIntegerByRef;
-        }
-        else
-        {
-            fieldClassificationType = CorInfoType2UnixAmd64Classification(fieldType);
-        }
+        SystemVClassificationType fieldClassificationType = CorInfoType2UnixAmd64Classification(fieldType);
 
 #ifdef _DEBUG
         LPCUTF8 fieldName;
index 57089d2..0bc8773 100644 (file)
@@ -8803,10 +8803,6 @@ MethodTableBuilder::HandleExplicitLayout(
     STANDARD_VM_CONTRACT;
     _ASSERTE(pMT->IsByRefLike());
 
-    // ByReference<T> is an indication for a byref field, treat it as such.
-    if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
-         return MarkTagType(pFieldLayout, TARGET_POINTER_SIZE, byref);
-
     ExplicitClassTrust explicitClassTrust;
 
     ExplicitFieldTrust::TrustLevel trust;
@@ -9902,9 +9898,6 @@ void MethodTableBuilder::CheckForSystemTypes()
 
         if (g_pNullableClass != NULL)
         {
-            _ASSERTE(g_pByReferenceClass != NULL);
-            _ASSERTE(g_pByReferenceClass->IsByRefLike());
-
             _ASSERTE(g_pNullableClass->IsNullable());
 
             // Pre-compute whether the class is a Nullable<T> so that code:Nullable::IsNullableType is efficient
index 93922dd..2665a46 100644 (file)
@@ -2262,7 +2262,6 @@ MarshalInfo::MarshalInfo(Module* pModule,
                     break;
 
                 // Blittable generics are allowed to be marshalled with the following exceptions:
-                // * ByReference<T>: This represents an interior pointer and is not actually blittable
                 // * Nullable<T>: We don't want to be locked into the default behavior as we may want special handling later
                 // * Vector64<T>: Represents the __m64 ABI primitive which requires currently unimplemented handling
                 // * Vector128<T>: Represents the __m128 ABI primitive which requires currently unimplemented handling
@@ -2272,7 +2271,6 @@ MarshalInfo::MarshalInfo(Module* pModule,
                 if (m_pMT->HasInstantiation() && !IsFieldScenario()
                     && (!m_pMT->IsBlittable()
                         || (m_pMT->HasSameTypeDefAs(g_pNullableClass)
-                        || m_pMT->HasSameTypeDefAs(g_pByReferenceClass)
                         || m_pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__SPAN))
                         || m_pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__READONLY_SPAN))
                         || m_pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTOR64T))
index 14766c1..a8d18ec 100644 (file)
@@ -4950,12 +4950,6 @@ public:
         _ASSERTE(pMT != nullptr);
         _ASSERTE(pMT->IsByRefLike());
 
-        if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
-        {
-            Report(baseOffset);
-            return;
-        }
-
         ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
         for (FieldDesc* pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
         {
index caa6cf4..522528a 100644 (file)
@@ -630,49 +630,28 @@ void TailCallHelp::CreateCallTargetStubSig(const TailCallInfo& info, SigBuilder*
 #endif // _DEBUG
 }
 
-// Get TypeHandle for ByReference<System.Byte>
-static TypeHandle GetByReferenceOfByteType()
+static TypeHandle GetByReferenceType()
 {
-    TypeHandle byteTH(CoreLibBinder::GetElementType(ELEMENT_TYPE_U1));
-    Instantiation byteInst(&byteTH, 1);
-    TypeHandle th = TypeHandle(CoreLibBinder::GetClass(CLASS__BYREFERENCE)).Instantiate(byteInst);
+    TypeHandle th = TypeHandle(CoreLibBinder::GetClass(CLASS__BYREFERENCE));
     return th;
 }
 
-// Get MethodDesc* for ByReference<System.Byte>::get_Value
-static MethodDesc* GetByReferenceOfByteValueGetter()
+static FieldDesc* GetByReferenceValueField()
 {
-    MethodDesc* getter = CoreLibBinder::GetMethod(METHOD__BYREFERENCE__GET_VALUE);
-    getter =
-        MethodDesc::FindOrCreateAssociatedMethodDesc(
-                getter,
-                GetByReferenceOfByteType().GetMethodTable(),
-                false,
-                Instantiation(),
-                TRUE);
-
-    return getter;
+    FieldDesc* pFD = CoreLibBinder::GetField(FIELD__BYREFERENCE__VALUE);
+    return pFD;
 }
 
-// Get MethodDesc* for ByReference<System.Byte>::.ctor
-static MethodDesc* GetByReferenceOfByteCtor()
+static MethodDesc* GetByReferenceOfCtor()
 {
-    MethodDesc* ctor = CoreLibBinder::GetMethod(METHOD__BYREFERENCE__CTOR);
-    ctor =
-        MethodDesc::FindOrCreateAssociatedMethodDesc(
-                ctor,
-                GetByReferenceOfByteType().GetMethodTable(),
-                false,
-                Instantiation(),
-                TRUE);
-
-    return ctor;
+    MethodDesc* pMD = CoreLibBinder::GetMethod(METHOD__BYREFERENCE__CTOR);
+    return pMD;
 }
 
 void TailCallHelp::EmitLoadTyHnd(ILCodeStream* stream, TypeHandle tyHnd)
 {
     if (tyHnd.IsByRef())
-        stream->EmitCALL(stream->GetToken(GetByReferenceOfByteValueGetter()), 1, 1);
+        stream->EmitLDFLD(stream->GetToken(GetByReferenceValueField()));
     else
         stream->EmitLDOBJ(stream->GetToken(tyHnd));
 }
@@ -681,8 +660,8 @@ void TailCallHelp::EmitStoreTyHnd(ILCodeStream* stream, TypeHandle tyHnd)
 {
     if (tyHnd.IsByRef())
     {
-        stream->EmitNEWOBJ(stream->GetToken(GetByReferenceOfByteCtor()), 1);
-        stream->EmitSTOBJ(stream->GetToken(GetByReferenceOfByteType()));
+        stream->EmitNEWOBJ(stream->GetToken(GetByReferenceOfCtor()), 1);
+        stream->EmitSTOBJ(stream->GetToken(GetByReferenceType()));
     }
     else
     {
index a796d58..d725b6f 100644 (file)
@@ -57,7 +57,6 @@ GPTR_IMPL(MethodTable,      g_pStringClass);
 GPTR_IMPL(MethodTable,      g_pArrayClass);
 GPTR_IMPL(MethodTable,      g_pSZArrayHelperClass);
 GPTR_IMPL(MethodTable,      g_pNullableClass);
-GPTR_IMPL(MethodTable,      g_pByReferenceClass);
 GPTR_IMPL(MethodTable,      g_pExceptionClass);
 GPTR_IMPL(MethodTable,      g_pThreadAbortExceptionClass);
 GPTR_IMPL(MethodTable,      g_pOutOfMemoryExceptionClass);
index c1de607..d6f8022 100644 (file)
@@ -363,7 +363,6 @@ GPTR_DECL(MethodTable,      g_pStringClass);
 GPTR_DECL(MethodTable,      g_pArrayClass);
 GPTR_DECL(MethodTable,      g_pSZArrayHelperClass);
 GPTR_DECL(MethodTable,      g_pNullableClass);
-GPTR_DECL(MethodTable,      g_pByReferenceClass);
 GPTR_DECL(MethodTable,      g_pExceptionClass);
 GPTR_DECL(MethodTable,      g_pThreadAbortExceptionClass);
 GPTR_DECL(MethodTable,      g_pOutOfMemoryExceptionClass);
index fabda09..b8f3b22 100644 (file)
@@ -6,6 +6,8 @@
     <NoWarn>$(NoWarn);SA1205;CA1845</NoWarn>
     <EnableTrimAnalyzer Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">false</EnableTrimAnalyzer>
     <IsPackable>true</IsPackable>
+    <!-- Lifetime rules introduced in C# 11 impact scenarios in net6 framework -->
+    <LangVersion Condition="'$(TargetFramework)' == 'net6.0'">10</LangVersion>
     <PackageDescription>Provides Classes that allow you to decouple code logging rich (unserializable) diagnostics/telemetry (e.g. framework) from code that consumes it (e.g. tools)
 
 Commonly Used Types:
index c96b01b..c2eca9b 100644 (file)
@@ -530,17 +530,7 @@ namespace System.Buffers.Text
         public static bool TryParse(System.ReadOnlySpan<byte> source, out ulong value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
     }
 }
-namespace System.Runtime.CompilerServices
-{
-    // See src\libraries\System.Private.CoreLib\src\System\Runtime\CompilerServices\LifetimeAnnotationAttribute.cs
-    [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
-    internal sealed class LifetimeAnnotationAttribute : System.Attribute
-    {
-        public LifetimeAnnotationAttribute(bool isRefScoped, bool isValueScoped) { throw null; }
-        public bool IsRefScoped { get { throw null; } }
-        public bool IsValueScoped { get { throw null; } }
-    }
-}
+
 namespace System.Runtime.InteropServices
 {
     public static partial class MemoryMarshal
@@ -553,16 +543,16 @@ namespace System.Runtime.InteropServices
         public static System.ReadOnlySpan<TTo> Cast<TFrom, TTo>(System.ReadOnlySpan<TFrom> span) where TFrom : struct where TTo : struct { throw null; }
         public static System.Span<TTo> Cast<TFrom, TTo>(System.Span<TFrom> span) where TFrom : struct where TTo : struct { throw null; }
         public static System.Memory<T> CreateFromPinnedArray<T>(T[]? array, int start, int length) { throw null; }
-        public static System.ReadOnlySpan<T> CreateReadOnlySpan<T>([System.Runtime.CompilerServices.LifetimeAnnotation(true, false)] ref T reference, int length) { throw null; }
+        public static System.ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref T reference, int length) { throw null; }
         [System.CLSCompliant(false)]
         public static unsafe ReadOnlySpan<byte> CreateReadOnlySpanFromNullTerminated(byte* value) { throw null; }
         [System.CLSCompliant(false)]
         public static unsafe ReadOnlySpan<char> CreateReadOnlySpanFromNullTerminated(char* value) { throw null; }
-        public static System.Span<T> CreateSpan<T>([System.Runtime.CompilerServices.LifetimeAnnotation(true, false)] ref T reference, int length) { throw null; }
+        public static System.Span<T> CreateSpan<T>(scoped ref T reference, int length) { throw null; }
         public static ref T GetArrayDataReference<T>(T[] array) { throw null; }
         public static ref byte GetArrayDataReference(System.Array array) { throw null; }
-        public static ref T GetReference<T>([System.Runtime.CompilerServices.LifetimeAnnotation(false, true)] System.ReadOnlySpan<T> span) { throw null; }
-        public static ref T GetReference<T>([System.Runtime.CompilerServices.LifetimeAnnotation(false, true)] System.Span<T> span) { throw null; }
+        public static ref T GetReference<T>(System.ReadOnlySpan<T> span) { throw null; }
+        public static ref T GetReference<T>(System.Span<T> span) { throw null; }
         public static T Read<T>(System.ReadOnlySpan<byte> source) where T : struct { throw null; }
         public static System.Collections.Generic.IEnumerable<T> ToEnumerable<T>(System.ReadOnlyMemory<T> memory) { throw null; }
         public static bool TryGetArray<T>(System.ReadOnlyMemory<T> memory, out System.ArraySegment<T> segment) { throw null; }
index 93eab8c..a079ceb 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\DefaultInterpolatedStringHandler.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IteratorStateMachineAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\ITuple.cs" />
-    <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\LifetimeAnnotationAttribute.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\LoadHint.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\MethodCodeType.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\MethodImplAttribute.cs" />
index bb58fc3..230a854 100644 (file)
@@ -6,36 +6,14 @@ using System.Runtime.Versioning;
 
 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.
+    // ByReference is meant to be used to represent a tracked reference in cases where C#
+    // proves difficult. See use in Reflection.
     [NonVersionable]
-    internal readonly ref struct ByReference<T>
+    internal readonly ref struct ByReference
     {
-#pragma warning disable CA1823, 169 // private field '{blah}' is never used
-        private readonly IntPtr _value;
-#pragma warning restore CA1823, 169
+        public readonly ref byte Value;
+        public ByReference(ref byte value) => Value = ref value;
 
-#pragma warning disable IDE0060
-        [Intrinsic]
-        public ByReference(ref T value)
-        {
-            // Implemented as a JIT intrinsic - This default implementation is for
-            // completeness and to provide a concrete error if called via reflection
-            // or if intrinsic is missed.
-            throw new PlatformNotSupportedException();
-        }
-#pragma warning restore IDE0060
-
-#pragma warning disable CA1822 // Mark members as static
-        public ref T Value
-        {
-            // Implemented as a JIT intrinsic - This default implementation is for
-            // completeness and to provide a concrete error if called via reflection
-            // or if the intrinsic is missed.
-            [Intrinsic]
-            get => throw new PlatformNotSupportedException();
-        }
-#pragma warning restore CA1822
+        public static ByReference Create<T>(ref T p) => new ByReference(ref Unsafe.As<T, byte>(ref p));
     }
 }
index cfdbe71..bb5917a 100644 (file)
@@ -299,7 +299,7 @@ namespace System
         // The pos should point to a quote character. This method will
         // append to the result StringBuilder the string enclosed by the quote character.
         //
-        internal static int ParseQuoteString(ReadOnlySpan<char> format, int pos, ref ValueStringBuilder result)
+        internal static int ParseQuoteString(scoped ReadOnlySpan<char> format, int pos, ref ValueStringBuilder result)
         {
             //
             // NOTE : pos will be the index of the quote character in the 'format' string.
@@ -444,7 +444,7 @@ namespace System
         //  Actions: Format the DateTime instance using the specified format.
         //
         private static void FormatCustomized(
-            DateTime dateTime, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, TimeSpan offset, ref ValueStringBuilder result)
+            DateTime dateTime, scoped ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, TimeSpan offset, ref ValueStringBuilder result)
         {
             Calendar cal = dtfi.Calendar;
 
index 8695e9b..f66e548 100644 (file)
@@ -300,7 +300,7 @@ namespace System.Globalization
         }
 
         /// <summary>Format the TimeSpan instance using the specified format.</summary>
-        private static void FormatCustomized(TimeSpan value, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, ref ValueStringBuilder result)
+        private static void FormatCustomized(TimeSpan value, scoped ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, ref ValueStringBuilder result)
         {
             Debug.Assert(dtfi != null);
 
index 68b2cbc..aca4b4f 100644 (file)
@@ -23,7 +23,7 @@ namespace System
     public readonly ref struct ReadOnlySpan<T>
     {
         /// <summary>A byref or a native ptr.</summary>
-        internal readonly ByReference<T> _reference;
+        internal readonly ref T _reference;
         /// <summary>The number of elements this ReadOnlySpan contains.</summary>
         private readonly int _length;
 
@@ -41,7 +41,7 @@ namespace System
                 return; // returns default
             }
 
-            _reference = new ByReference<T>(ref MemoryMarshal.GetArrayDataReference(array));
+            _reference = ref MemoryMarshal.GetArrayDataReference(array);
             _length = array.Length;
         }
 
@@ -75,7 +75,7 @@ namespace System
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 #endif
 
-            _reference = new ByReference<T>(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */));
+            _reference = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */);
             _length = length;
         }
 
@@ -102,7 +102,7 @@ namespace System
             if (length < 0)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            _reference = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
+            _reference = ref Unsafe.As<byte, T>(ref *(byte*)pointer);
             _length = length;
         }
 
@@ -112,7 +112,7 @@ namespace System
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal ReadOnlySpan(in T reference)
         {
-            _reference = new ByReference<T>(ref Unsafe.AsRef(in reference));
+            _reference = ref Unsafe.AsRef(in reference);
             _length = 1;
         }
 
@@ -122,7 +122,7 @@ namespace System
         {
             Debug.Assert(length >= 0);
 
-            _reference = new ByReference<T>(ref reference);
+            _reference = ref reference;
             _length = length;
         }
 
@@ -143,7 +143,7 @@ namespace System
             {
                 if ((uint)index >= (uint)_length)
                     ThrowHelper.ThrowIndexOutOfRangeException();
-                return ref Unsafe.Add(ref _reference.Value, (nint)(uint)index /* force zero-extension */);
+                return ref Unsafe.Add(ref _reference, (nint)(uint)index /* force zero-extension */);
             }
         }
 
@@ -261,7 +261,7 @@ namespace System
         {
             // Ensure that the native code has just one forward branch that is predicted-not-taken.
             ref T ret = ref Unsafe.NullRef<T>();
-            if (_length != 0) ret = ref _reference.Value;
+            if (_length != 0) ret = ref _reference;
             return ref ret;
         }
 
@@ -284,7 +284,7 @@ namespace System
 
             if ((uint)_length <= (uint)destination.Length)
             {
-                Buffer.Memmove(ref destination._reference.Value, ref _reference.Value, (uint)_length);
+                Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length);
             }
             else
             {
@@ -305,7 +305,7 @@ namespace System
             bool retVal = false;
             if ((uint)_length <= (uint)destination.Length)
             {
-                Buffer.Memmove(ref destination._reference.Value, ref _reference.Value, (uint)_length);
+                Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length);
                 retVal = true;
             }
             return retVal;
@@ -317,7 +317,7 @@ namespace System
         /// </summary>
         public static bool operator ==(ReadOnlySpan<T> left, ReadOnlySpan<T> right) =>
             left._length == right._length &&
-            Unsafe.AreSame<T>(ref left._reference.Value, ref right._reference.Value);
+            Unsafe.AreSame<T>(ref left._reference, ref right._reference);
 
         /// <summary>
         /// For <see cref="ReadOnlySpan{Char}"/>, returns a new instance of string that represents the characters pointed to by the span.
@@ -327,7 +327,7 @@ namespace System
         {
             if (typeof(T) == typeof(char))
             {
-                return new string(new ReadOnlySpan<char>(ref Unsafe.As<T, char>(ref _reference.Value), _length));
+                return new string(new ReadOnlySpan<char>(ref Unsafe.As<T, char>(ref _reference), _length));
             }
             return $"System.ReadOnlySpan<{typeof(T).Name}>[{_length}]";
         }
@@ -345,7 +345,7 @@ namespace System
             if ((uint)start > (uint)_length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new ReadOnlySpan<T>(ref Unsafe.Add(ref _reference.Value, (nint)(uint)start /* force zero-extension */), _length - start);
+            return new ReadOnlySpan<T>(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), _length - start);
         }
 
         /// <summary>
@@ -368,7 +368,7 @@ namespace System
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 #endif
 
-            return new ReadOnlySpan<T>(ref Unsafe.Add(ref _reference.Value, (nint)(uint)start /* force zero-extension */), length);
+            return new ReadOnlySpan<T>(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), length);
         }
 
         /// <summary>
@@ -382,7 +382,7 @@ namespace System
                 return Array.Empty<T>();
 
             var destination = new T[_length];
-            Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _reference.Value, (uint)_length);
+            Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _reference, (uint)_length);
             return destination;
         }
     }
index 00ff3ce..4e4bab9 100644 (file)
@@ -55,7 +55,7 @@ namespace System.Reflection
                     il.Emit(OpCodes.Add);
                 }
 
-                il.Emit(OpCodes.Call, Methods.ByReferenceOfByte_Value()); // This can be replaced by ldfld once byref fields are available in C#
+                il.Emit(OpCodes.Ldfld, Methods.ByReferenceOfByte_Value());
 
                 RuntimeType parameterType = (RuntimeType)parameters[i].ParameterType;
                 if (!parameterType.IsByRef)
@@ -166,9 +166,9 @@ namespace System.Reflection
 
         private static class Methods
         {
-            private static MethodInfo? s_ByReferenceOfByte_Value;
-            public static MethodInfo ByReferenceOfByte_Value() =>
-                s_ByReferenceOfByte_Value ??= typeof(ByReference<byte>).GetMethod("get_Value")!;
+            private static FieldInfo? s_ByReferenceOfByte_Value;
+            public static FieldInfo ByReferenceOfByte_Value() =>
+                s_ByReferenceOfByte_Value ??= typeof(ByReference).GetField("Value")!;
 
             private static MethodInfo? s_ThrowHelper_Throw_NullReference_InvokeNullRefReturned;
             public static MethodInfo ThrowHelper_Throw_NullReference_InvokeNullRefReturned() =>
index 36d40f1..f91ad52 100644 (file)
@@ -234,13 +234,13 @@ namespace System.Reflection
                         (sigType.IsByRef && arg.GetType() == RuntimeTypeHandle.GetElementType(sigType)) ||
                         ((sigType.IsEnum || arg.GetType().IsEnum) && RuntimeType.GetUnderlyingType((RuntimeType)arg.GetType()) == RuntimeType.GetUnderlyingType(sigType)));
 #endif
-                    ByReference<byte> valueTypeRef = new(ref copyOfParameters[i]!.GetRawData());
-                    *(ByReference<byte>*)(byrefParameters + i) = valueTypeRef;
+                    ByReference valueTypeRef = ByReference.Create(ref copyOfParameters[i]!.GetRawData());
+                    *(ByReference*)(byrefParameters + i) = valueTypeRef;
                 }
                 else
                 {
-                    ByReference<object?> objRef = new(ref copyOfParameters[i]);
-                    *(ByReference<object?>*)(byrefParameters + i) = objRef;
+                    ByReference objRef = ByReference.Create(ref copyOfParameters[i]);
+                    *(ByReference*)(byrefParameters + i) = objRef;
                 }
             }
         }
@@ -273,11 +273,11 @@ namespace System.Reflection
         [StructLayout(LayoutKind.Sequential)]
         private protected ref struct StackAllocatedByRefs
         {
-            internal ByReference<byte> _arg0;
+            internal ref byte _arg0;
 #pragma warning disable CA1823, CS0169, IDE0051 // accessed via 'CheckArguments' ref arithmetic
-            private ByReference<byte> _arg1;
-            private ByReference<byte> _arg2;
-            private ByReference<byte> _arg3;
+            private ref byte _arg1;
+            private ref byte _arg2;
+            private ref byte _arg3;
 #pragma warning restore CA1823, CS0169, IDE0051
         }
 #endif
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/LifetimeAnnotationAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/LifetimeAnnotationAttribute.cs
deleted file mode 100644 (file)
index f792a7a..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-
-namespace System.Runtime.CompilerServices
-{
-    /// <summary>
-    /// This type is defined until we consume the C# 11 compiler.
-    /// </summary>
-    /// <remarks>
-    /// Also remove in the reference assemblies.
-    /// </remarks>
-    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
-    internal sealed class LifetimeAnnotationAttribute : Attribute
-    {
-        public LifetimeAnnotationAttribute(bool isRefScoped, bool isValueScoped)
-        {
-            IsRefScoped = isRefScoped;
-            IsValueScoped = isValueScoped;
-        }
-        public bool IsRefScoped { get; }
-        public bool IsValueScoped { get; }
-    }
-}
index d006bd5..1f2181b 100644 (file)
@@ -665,13 +665,14 @@ namespace System.Runtime.CompilerServices
         /// <summary>
         /// Reinterprets the given location as a reference to a value of type <typeparamref name="T"/>.
         /// </summary>
+        /// <remarks>The lifetime of the reference will not be validated when using this API.</remarks>
         [Intrinsic]
         // CoreCLR:METHOD__UNSAFE__AS_REF_IN
         // AOT:AsRef
         // Mono:AsRef
         [NonVersionable]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static ref T AsRef<T>([LifetimeAnnotation(true, false)] in T source)
+        public static ref T AsRef<T>(scoped in T source)
         {
             throw new PlatformNotSupportedException();
 
index f089434..c91aa21 100644 (file)
@@ -77,27 +77,27 @@ namespace System.Runtime.InteropServices
         /// 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 may or may not be null. It can be used for pinning but must never be dereferenced.
         /// </summary>
-        public static ref T GetReference<T>([LifetimeAnnotation(false, true)] Span<T> span) => ref span._reference.Value;
+        public static ref T GetReference<T>(Span<T> span) => ref span._reference;
 
         /// <summary>
         /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to the location where the 0th element
         /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced.
         /// </summary>
-        public static ref T GetReference<T>([LifetimeAnnotation(false, true)] ReadOnlySpan<T> span) => ref span._reference.Value;
+        public static ref T GetReference<T>(ReadOnlySpan<T> span) => ref span._reference;
 
         /// <summary>
         /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to fake non-null pointer. Such a reference can be used
         /// for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
         /// </summary>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static unsafe ref T GetNonNullPinnableReference<T>(Span<T> span) => ref (span.Length != 0) ? ref span._reference.Value : ref Unsafe.AsRef<T>((void*)1);
+        internal static unsafe ref T GetNonNullPinnableReference<T>(Span<T> span) => ref (span.Length != 0) ? ref Unsafe.AsRef<T>(in span._reference) : ref Unsafe.AsRef<T>((void*)1);
 
         /// <summary>
         /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to fake non-null pointer. Such a reference
         /// can be used for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
         /// </summary>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static unsafe ref T GetNonNullPinnableReference<T>(ReadOnlySpan<T> span) => ref (span.Length != 0) ? ref span._reference.Value : ref Unsafe.AsRef<T>((void*)1);
+        internal static unsafe ref T GetNonNullPinnableReference<T>(ReadOnlySpan<T> span) => ref (span.Length != 0) ? ref Unsafe.AsRef<T>(in span._reference) : ref Unsafe.AsRef<T>((void*)1);
 
         /// <summary>
         /// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
@@ -150,7 +150,7 @@ namespace System.Runtime.InteropServices
             }
 
             return new Span<TTo>(
-                ref Unsafe.As<TFrom, TTo>(ref span._reference.Value),
+                ref Unsafe.As<TFrom, TTo>(ref span._reference),
                 toLength);
         }
 
@@ -217,9 +217,14 @@ namespace System.Runtime.InteropServices
         /// <param name="reference">A reference to data.</param>
         /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
         /// <returns>A span representing the specified reference and length.</returns>
-        /// <remarks>The lifetime of the returned span will not be validated for safety by span-aware languages.</remarks>
+        /// <remarks>
+        /// This method should be used with caution. It is dangerous because the length argument is not checked.
+        /// Even though the ref is annotated as scoped, it will be stored into the returned span, and the lifetime
+        /// of the returned span will not be validated for safety, even by span-aware languages.
+        /// </remarks>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static Span<T> CreateSpan<T>([LifetimeAnnotation(true, false)] ref T reference, int length) => new Span<T>(ref reference, length);
+        public static Span<T> CreateSpan<T>(scoped ref T reference, int length) =>
+            new Span<T>(ref Unsafe.AsRef(in reference), length);
 
         /// <summary>
         /// Creates a new read-only span over a portion of a regular managed object. This can be useful
@@ -229,9 +234,14 @@ namespace System.Runtime.InteropServices
         /// <param name="reference">A reference to data.</param>
         /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
         /// <returns>A read-only span representing the specified reference and length.</returns>
-        /// <remarks>The lifetime of the returned span will not be validated for safety by span-aware languages.</remarks>
+        /// <remarks>
+        /// This method should be used with caution. It is dangerous because the length argument is not checked.
+        /// Even though the ref is annotated as scoped, it will be stored into the returned span, and the lifetime
+        /// of the returned span will not be validated for safety, even by span-aware languages.
+        /// </remarks>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static ReadOnlySpan<T> CreateReadOnlySpan<T>([LifetimeAnnotation(true, false)] ref T reference, int length) => new ReadOnlySpan<T>(ref reference, length);
+        public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref T reference, int length) =>
+            new ReadOnlySpan<T>(ref Unsafe.AsRef(in reference), length);
 
         /// <summary>Creates a new read-only span for a null-terminated string.</summary>
         /// <param name="value">The pointer to the null-terminated string of characters.</param>
index 74c80a8..6ecf1ae 100644 (file)
@@ -22,7 +22,7 @@ namespace System
     public readonly ref struct Span<T>
     {
         /// <summary>A byref or a native ptr.</summary>
-        internal readonly ByReference<T> _reference;
+        internal readonly ref T _reference;
         /// <summary>The number of elements this Span contains.</summary>
         private readonly int _length;
 
@@ -43,7 +43,7 @@ namespace System
             if (!typeof(T).IsValueType && array.GetType() != typeof(T[]))
                 ThrowHelper.ThrowArrayTypeMismatchException();
 
-            _reference = new ByReference<T>(ref MemoryMarshal.GetArrayDataReference(array));
+            _reference = ref MemoryMarshal.GetArrayDataReference(array);
             _length = array.Length;
         }
 
@@ -80,7 +80,7 @@ namespace System
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 #endif
 
-            _reference = new ByReference<T>(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */));
+            _reference = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */);
             _length = length;
         }
 
@@ -107,7 +107,7 @@ namespace System
             if (length < 0)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            _reference = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
+            _reference = ref Unsafe.As<byte, T>(ref *(byte*)pointer);
             _length = length;
         }
 
@@ -117,7 +117,7 @@ namespace System
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal Span(ref T reference)
         {
-            _reference = new ByReference<T>(ref reference);
+            _reference = ref reference;
             _length = 1;
         }
 
@@ -127,7 +127,7 @@ namespace System
         {
             Debug.Assert(length >= 0);
 
-            _reference = new ByReference<T>(ref reference);
+            _reference = ref reference;
             _length = length;
         }
 
@@ -148,7 +148,7 @@ namespace System
             {
                 if ((uint)index >= (uint)_length)
                     ThrowHelper.ThrowIndexOutOfRangeException();
-                return ref Unsafe.Add(ref _reference.Value, (nint)(uint)index /* force zero-extension */);
+                return ref Unsafe.Add(ref _reference, (nint)(uint)index /* force zero-extension */);
             }
         }
 
@@ -266,7 +266,7 @@ namespace System
         {
             // Ensure that the native code has just one forward branch that is predicted-not-taken.
             ref T ret = ref Unsafe.NullRef<T>();
-            if (_length != 0) ret = ref _reference.Value;
+            if (_length != 0) ret = ref _reference;
             return ref ret;
         }
 
@@ -278,11 +278,11 @@ namespace System
         {
             if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
             {
-                SpanHelpers.ClearWithReferences(ref Unsafe.As<T, IntPtr>(ref _reference.Value), (uint)_length * (nuint)(Unsafe.SizeOf<T>() / sizeof(nuint)));
+                SpanHelpers.ClearWithReferences(ref Unsafe.As<T, IntPtr>(ref _reference), (uint)_length * (nuint)(Unsafe.SizeOf<T>() / sizeof(nuint)));
             }
             else
             {
-                SpanHelpers.ClearWithoutReferences(ref Unsafe.As<T, byte>(ref _reference.Value), (uint)_length * (nuint)Unsafe.SizeOf<T>());
+                SpanHelpers.ClearWithoutReferences(ref Unsafe.As<T, byte>(ref _reference), (uint)_length * (nuint)Unsafe.SizeOf<T>());
             }
         }
 
@@ -298,12 +298,12 @@ namespace System
                 // The runtime eventually calls memset, which can efficiently support large buffers.
                 // We don't need to check IsReferenceOrContainsReferences because no references
                 // can ever be stored in types this small.
-                Unsafe.InitBlockUnaligned(ref Unsafe.As<T, byte>(ref _reference.Value), Unsafe.As<T, byte>(ref value), (uint)_length);
+                Unsafe.InitBlockUnaligned(ref Unsafe.As<T, byte>(ref _reference), Unsafe.As<T, byte>(ref value), (uint)_length);
             }
             else
             {
                 // Call our optimized workhorse method for all other types.
-                SpanHelpers.Fill(ref _reference.Value, (uint)_length, value);
+                SpanHelpers.Fill(ref _reference, (uint)_length, value);
             }
         }
 
@@ -325,7 +325,7 @@ namespace System
 
             if ((uint)_length <= (uint)destination.Length)
             {
-                Buffer.Memmove(ref destination._reference.Value, ref _reference.Value, (uint)_length);
+                Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length);
             }
             else
             {
@@ -346,7 +346,7 @@ namespace System
             bool retVal = false;
             if ((uint)_length <= (uint)destination.Length)
             {
-                Buffer.Memmove(ref destination._reference.Value, ref _reference.Value, (uint)_length);
+                Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length);
                 retVal = true;
             }
             return retVal;
@@ -358,13 +358,13 @@ namespace System
         /// </summary>
         public static bool operator ==(Span<T> left, Span<T> right) =>
             left._length == right._length &&
-            Unsafe.AreSame<T>(ref left._reference.Value, ref right._reference.Value);
+            Unsafe.AreSame<T>(ref left._reference, ref right._reference);
 
         /// <summary>
         /// Defines an implicit conversion of a <see cref="Span{T}"/> to a <see cref="ReadOnlySpan{T}"/>
         /// </summary>
         public static implicit operator ReadOnlySpan<T>(Span<T> span) =>
-            new ReadOnlySpan<T>(ref span._reference.Value, span._length);
+            new ReadOnlySpan<T>(ref span._reference, span._length);
 
         /// <summary>
         /// For <see cref="Span{Char}"/>, returns a new instance of string that represents the characters pointed to by the span.
@@ -374,7 +374,7 @@ namespace System
         {
             if (typeof(T) == typeof(char))
             {
-                return new string(new ReadOnlySpan<char>(ref Unsafe.As<T, char>(ref _reference.Value), _length));
+                return new string(new ReadOnlySpan<char>(ref Unsafe.As<T, char>(ref _reference), _length));
             }
             return $"System.Span<{typeof(T).Name}>[{_length}]";
         }
@@ -392,7 +392,7 @@ namespace System
             if ((uint)start > (uint)_length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new Span<T>(ref Unsafe.Add(ref _reference.Value, (nint)(uint)start /* force zero-extension */), _length - start);
+            return new Span<T>(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), _length - start);
         }
 
         /// <summary>
@@ -420,7 +420,7 @@ namespace System
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 #endif
 
-            return new Span<T>(ref Unsafe.Add(ref _reference.Value, (nint)(uint)start /* force zero-extension */), length);
+            return new Span<T>(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), length);
         }
 
         /// <summary>
@@ -435,7 +435,7 @@ namespace System
                 return Array.Empty<T>();
 
             var destination = new T[_length];
-            Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _reference.Value, (uint)_length);
+            Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _reference, (uint)_length);
             return destination;
         }
     }
index 0923eb4..9ac73fb 100644 (file)
@@ -419,7 +419,7 @@ namespace System
         {
             if ((uint)Length <= (uint)destination.Length)
             {
-                Buffer.Memmove(ref destination._reference.Value, ref _firstChar, (uint)Length);
+                Buffer.Memmove(ref destination._reference, ref _firstChar, (uint)Length);
             }
             else
             {
@@ -436,7 +436,7 @@ namespace System
             bool retVal = false;
             if ((uint)Length <= (uint)destination.Length)
             {
-                Buffer.Memmove(ref destination._reference.Value, ref _firstChar, (uint)Length);
+                Buffer.Memmove(ref destination._reference, ref _firstChar, (uint)Length);
                 retVal = true;
             }
             return retVal;
index 99aec15..3e164bc 100644 (file)
@@ -1007,7 +1007,7 @@ namespace System
             return !standardName.IsEmpty && !standardOffset.IsEmpty;
         }
 
-        private static ReadOnlySpan<char> TZif_ParsePosixName(ReadOnlySpan<char> posixFormat, ref int index)
+        private static ReadOnlySpan<char> TZif_ParsePosixName(ReadOnlySpan<char> posixFormat, scoped ref int index)
         {
             bool isBracketEnclosed = index < posixFormat.Length && posixFormat[index] == '<';
             if (isBracketEnclosed)
@@ -1034,10 +1034,10 @@ namespace System
             }
         }
 
-        private static ReadOnlySpan<char> TZif_ParsePosixOffset(ReadOnlySpan<char> posixFormat, ref int index) =>
+        private static ReadOnlySpan<char> TZif_ParsePosixOffset(ReadOnlySpan<char> posixFormat, scoped ref int index) =>
             TZif_ParsePosixString(posixFormat, ref index, c => !char.IsDigit(c) && c != '+' && c != '-' && c != ':');
 
-        private static void TZif_ParsePosixDateTime(ReadOnlySpan<char> posixFormat, ref int index, out ReadOnlySpan<char> date, out ReadOnlySpan<char> time)
+        private static void TZif_ParsePosixDateTime(ReadOnlySpan<char> posixFormat, scoped ref int index, out ReadOnlySpan<char> date, out ReadOnlySpan<char> time)
         {
             time = null;
 
@@ -1049,13 +1049,13 @@ namespace System
             }
         }
 
-        private static ReadOnlySpan<char> TZif_ParsePosixDate(ReadOnlySpan<char> posixFormat, ref int index) =>
+        private static ReadOnlySpan<char> TZif_ParsePosixDate(ReadOnlySpan<char> posixFormat, scoped ref int index) =>
             TZif_ParsePosixString(posixFormat, ref index, c => c == '/' || c == ',');
 
-        private static ReadOnlySpan<char> TZif_ParsePosixTime(ReadOnlySpan<char> posixFormat, ref int index) =>
+        private static ReadOnlySpan<char> TZif_ParsePosixTime(ReadOnlySpan<char> posixFormat, scoped ref int index) =>
             TZif_ParsePosixString(posixFormat, ref index, c => c == ',');
 
-        private static ReadOnlySpan<char> TZif_ParsePosixString(ReadOnlySpan<char> posixFormat, ref int index, Func<char, bool> breakCondition)
+        private static ReadOnlySpan<char> TZif_ParsePosixString(ReadOnlySpan<char> posixFormat, scoped ref int index, Func<char, bool> breakCondition)
         {
             int startIndex = index;
             for (; index < posixFormat.Length; index++)
index dd13bfd..2ff8dc7 100644 (file)
@@ -75,7 +75,7 @@ namespace System
             throw new NotSupportedException(SR.NotSupported_NYI);
         }
 
-        internal bool IsNull => Unsafe.IsNullRef(ref _value.Value) && _type == IntPtr.Zero;
+        internal bool IsNull => Unsafe.IsNullRef(ref _value) && _type == IntPtr.Zero;
 
         public static Type GetTargetType(TypedReference value)
         {
index 0a04f25..b1ae8a2 100644 (file)
@@ -133,7 +133,7 @@ namespace System.Runtime.Serialization.Formatters.Tests
 
         [Theory]
         [MemberData(nameof(GetUninitializedObject_ByRefLikeType_NetCore_TestData))]
-        [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp, "Some runtimes don't support or recognise Span<T>, ReadOnlySpan<T> or ByReference<T> as ref types.")]
+        [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp, "Some runtimes don't support or recognise Span<T> or ReadOnlySpan<T> as ref types.")]
         public void GetUninitializedObject_ByRefLikeType_NetCore_ThrowsNotSupportedException(Type type)
         {
             Assert.Throws<NotSupportedException>(() => FormatterServices.GetUninitializedObject(type));
index 16b2ec8..62dd38c 100644 (file)
@@ -12538,14 +12538,6 @@ namespace System.Runtime.CompilerServices
         object? this[int index] { get; }
         int Length { get; }
     }
-    // See src\libraries\System.Private.CoreLib\src\System\Runtime\CompilerServices\LifetimeAnnotationAttribute.cs
-    [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
-    internal sealed class LifetimeAnnotationAttribute : System.Attribute
-    {
-        public LifetimeAnnotationAttribute(bool isRefScoped, bool isValueScoped) { throw null; }
-        public bool IsRefScoped { get { throw null; } }
-        public bool IsValueScoped { get { throw null; } }
-    }
     public enum LoadHint
     {
         Default = 0,
@@ -12789,7 +12781,7 @@ namespace System.Runtime.CompilerServices
         public unsafe static void* AsPointer<T>(ref T value) { throw null; }
         [System.CLSCompliantAttribute(false)]
         public unsafe static ref T AsRef<T>(void* source) { throw null; }
-        public static ref T AsRef<T>([System.Runtime.CompilerServices.LifetimeAnnotation(true, false)] in T source) { throw null; }
+        public static ref T AsRef<T>(scoped in T source) { throw null; }
         [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("o")]
         public static T? As<T>(object? o) where T : class? { throw null; }
         public static ref TTo As<TFrom, TTo>(ref TFrom source) { throw null; }
index f7a473b..d9003bf 100644 (file)
@@ -11,7 +11,7 @@ namespace System
         #region sync with object-internals.h
         #pragma warning disable CA1823 // used by runtime
         private readonly RuntimeTypeHandle type;
-        private readonly ByReference<byte> _value;
+        private readonly ref byte _value;
         private readonly IntPtr _type;
         #pragma warning restore CA1823
         #endregion
index 7619ebe..2e28b81 100644 (file)
@@ -1836,34 +1836,11 @@ class_has_ref_fields (MonoClass *klass)
 }
 
 static gboolean
-class_is_byreference (MonoClass* klass)
-{
-       const char* klass_name_space = m_class_get_name_space (klass);
-       const char* klass_name = m_class_get_name (klass);
-       MonoImage* klass_image = m_class_get_image (klass);
-       gboolean in_corlib = klass_image == mono_defaults.corlib;
-
-       if (in_corlib &&
-               !strcmp (klass_name_space, "System") &&
-               !strcmp (klass_name, "ByReference`1")) {
-               return TRUE;
-       }
-
-       return FALSE;
-}
-
-static gboolean
 type_has_ref_fields (MonoType *ftype)
 {
        if (m_type_is_byref (ftype) || (MONO_TYPE_ISSTRUCT (ftype) && class_has_ref_fields (mono_class_from_mono_type_internal (ftype))))
                return TRUE;
 
-       /* Check for the ByReference`1 type */
-       if (MONO_TYPE_ISSTRUCT (ftype)) {
-               MonoClass* klass = mono_class_from_mono_type_internal (ftype);
-               return class_is_byreference (klass);
-       }
-
        return FALSE;
 }
 
@@ -1982,7 +1959,7 @@ validate_struct_fields_overlaps (guint8 *layout_check, int layout_size, MonoClas
                } else {
                        int align = 0;
                        int size = mono_type_size (field->type, &align);
-                       guint8 type = type_has_references (klass, ftype) ? 1 : (m_type_is_byref (ftype) || class_is_byreference (klass)) ? 2 : 3;
+                       guint8 type = type_has_references (klass, ftype) ? 1 : m_type_is_byref (ftype) ? 2 : 3;
 
                        // Mark the bytes used by this fields type based on if it contains references or not.
                        // Make sure there are no overlaps between object and non-object fields.
index 9479611..74f3672 100644 (file)
@@ -830,9 +830,7 @@ mono_marshal_shared_emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *kla
                case MONO_MARSHAL_CONV_NONE: {
                        int t;
 
-                       //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
-                       g_assert (!m_type_is_byref (ftype));
-                       if (ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) {
+                       if (m_type_is_byref (ftype) || ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) {
                                mono_mb_emit_ldloc (mb, 1);
                                mono_mb_emit_ldloc (mb, 0);
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
index ed3a579..6f998c8 100644 (file)
@@ -3342,10 +3342,8 @@ static long opcode_counts[MINT_LASTOP];
        if (tracing > 1) { \
                output_indent (); \
                char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
-               char *disasm = mono_interp_dis_mintop ((gint32)(ip - frame->imethod->code), TRUE, ip + 1, *ip); \
-               g_print ("(%p) %s -> %s\n", mono_thread_internal_current (), mn, disasm); \
+               g_print ("(%p) %s -> IL_%04x: %-10s\n", mono_thread_internal_current (), mn, (gint32)(ip - frame->imethod->code), mono_interp_opname (*ip)); \
                g_free (mn); \
-               g_free (disasm); \
        }
 #else
 #define DUMP_INSTR()
index bcbc773..a65b355 100644 (file)
@@ -1862,9 +1862,6 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas
                        !strcmp (klass_name, "SpanHelpers") &&
                        !strcmp (tm, "ClearWithReferences")) {
                *op = MINT_INTRINS_CLEAR_WITH_REFERENCES;
-       } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "ByReference`1")) {
-               g_assert (!strcmp (tm, "get_Value"));
-               *op = MINT_LDIND_I;
        } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "Marvin")) {
                if (!strcmp (tm, "Block")) {
                        InterpInst *ldloca2 = td->last_ins;
@@ -5552,18 +5549,6 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
                                td->last_ins->flags |= INTERP_INST_FLAG_CALL;
                                td->last_ins->info.call_args = call_args;
                        } else if (m_class_get_image (klass) == mono_defaults.corlib &&
-                                       !strcmp (m_class_get_name (m->klass), "ByReference`1") &&
-                                       !strcmp (m->name, ".ctor")) {
-                               /* public ByReference(ref T value) */
-                               MONO_PROFILER_RAISE (inline_method, (td->rtm->method, m));
-                               g_assert (csignature->hasthis && csignature->param_count == 1);
-                               td->sp--;
-                               /* We already have the vt on top of the stack. Just do a dummy mov that should be optimized out */
-                               interp_add_ins (td, MINT_MOV_P);
-                               interp_ins_set_sreg (td->last_ins, td->sp [0].local);
-                               push_type_vt (td, klass, mono_class_value_size (klass, NULL));
-                               interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
-                       } else if (m_class_get_image (klass) == mono_defaults.corlib &&
                                        (!strcmp (m_class_get_name (m->klass), "Span`1") ||
                                        !strcmp (m_class_get_name (m->klass), "ReadOnlySpan`1")) &&
                                        csignature->param_count == 2 &&
@@ -5834,7 +5819,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
                        mono_class_init_internal (klass);
 
                        MonoClass *field_klass = mono_class_from_mono_type_internal (ftype);
-                       mt = mint_type (m_class_get_byval_arg (field_klass));
+                       mt = mint_type (ftype);
                        int field_size = mono_class_value_size (field_klass, NULL);
                        int obj_size = mono_class_value_size (klass, NULL);
                        obj_size = ALIGN_TO (obj_size, MINT_VT_ALIGNMENT);
index 17b78eb..53ccc07 100644 (file)
@@ -75,24 +75,12 @@ mono_type_is_native_blittable (MonoType *t)
 MonoInst*
 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
-       const char* cmethod_klass_name_space = m_class_get_name_space (cmethod->klass);
-       const char* cmethod_klass_name = m_class_get_name (cmethod->klass);
-       MonoImage *cmethod_klass_image = m_class_get_image (cmethod->klass);
-       gboolean in_corlib = cmethod_klass_image == mono_defaults.corlib;
        MonoInst *ins = NULL;
 
        /* Required intrinsics are always used even with -O=-intrins */
-       if (in_corlib &&
-               !strcmp (cmethod_klass_name_space, "System") &&
-               !strcmp (cmethod_klass_name, "ByReference`1")) {
-               /* public ByReference(ref T value) */
-               g_assert (fsig->hasthis && fsig->param_count == 1);
-               EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [0]->dreg, 0, args [1]->dreg);
-               return ins;
-       }
 
        if (!(cfg->opt & MONO_OPT_INTRINS))
-               return NULL;
+               return ins;
 
 #ifdef MONO_ARCH_SIMD_INTRINSICS
        if (cfg->opt & MONO_OPT_SIMD) {
@@ -102,7 +90,7 @@ mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignat
        }
 #endif
 
-       return NULL;
+       return ins;
 }
 
 static MonoInst*
@@ -806,15 +794,6 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
        gboolean in_corlib = cmethod_klass_image == mono_defaults.corlib;
 
        /* Required intrinsics are always used even with -O=-intrins */
-       if (in_corlib &&
-               !strcmp (cmethod_klass_name_space, "System") &&
-               !strcmp (cmethod_klass_name, "ByReference`1") &&
-               !strcmp (cmethod->name, "get_Value")) {
-               g_assert (fsig->hasthis && fsig->param_count == 0);
-               int dreg = alloc_preg (cfg);
-               EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, args [0]->dreg, 0);
-               return ins;
-       }
 
        if (!(cfg->opt & MONO_OPT_INTRINS))
                return NULL;