Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consume Roslyn with ref fields support #71498

Merged
merged 25 commits into from
Jul 2, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bafbf1d
Use C# ref field support
AaronRobinsonMSFT May 18, 2022
7af11d6
Update coreclr/vm to remove knowledge of ByReference<T>
AaronRobinsonMSFT May 18, 2022
b39eaa7
Update coreclr/jit to remove ByReference<T> intrinsics
AaronRobinsonMSFT May 18, 2022
bcb19b4
Create new ByReference to be used in Reflection and tailcall slow paths
AaronRobinsonMSFT May 18, 2022
0ffd2dc
Remove ByReference<T> from crossgen/aot code base
AaronRobinsonMSFT May 18, 2022
d7adc38
Remove ByReference<T> from mono/
AaronRobinsonMSFT May 18, 2022
9bb79ef
Limit net6.0 TFM in DiagnosticsSource to C# 10.
AaronRobinsonMSFT May 19, 2022
9f1ec73
Merge remote-tracking branch 'upstream/main' into feature/csharp_ref_…
AaronRobinsonMSFT Jun 23, 2022
b4042b9
Apply more fixes
AaronRobinsonMSFT Jun 24, 2022
a87752f
Remove unnecessary scoped on GetReference API.
AaronRobinsonMSFT Jun 24, 2022
0430f85
Merge remote-tracking branch 'upstream/main' into feature/csharp_ref_…
AaronRobinsonMSFT Jun 30, 2022
a30d754
Remove temporary LifetimeAnnotationAttribute
AaronRobinsonMSFT Jun 30, 2022
73a85a5
Update to Roslyn compiler with ref field support.
AaronRobinsonMSFT Jun 30, 2022
c496c66
Update for compiler warning/error.
AaronRobinsonMSFT Jun 30, 2022
b074436
Review feedback.
AaronRobinsonMSFT Jun 30, 2022
bafd6cf
Treat a byref as a native pointer.
AaronRobinsonMSFT Jul 1, 2022
e785b70
Remove unnecessary Unsafe.AsRef<T> usage.
AaronRobinsonMSFT Jul 1, 2022
51089af
Remove missed mention of ByReference<T>.
AaronRobinsonMSFT Jul 1, 2022
82eb3ce
Update comments with those approved in official docs.
AaronRobinsonMSFT Jul 1, 2022
fa5ea6c
Bring back recognition of the ByReference type
AaronRobinsonMSFT Jul 1, 2022
3180604
Revert "Bring back recognition of the ByReference type"
AaronRobinsonMSFT Jul 2, 2022
362df63
Handle byref field in interpreter
AaronRobinsonMSFT Jul 2, 2022
b9f4948
Fix build break when DEBUG_INTERP defined.
AaronRobinsonMSFT Jul 2, 2022
8e09487
Merge remote-tracking branch 'upstream/main' into feature/csharp_ref_…
AaronRobinsonMSFT Jul 2, 2022
0d0c9de
Feedback and build breaks.
AaronRobinsonMSFT Jul 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -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 -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -38,11 +38,11 @@ public ref partial struct TypedReference

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;
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/inc/dacvars.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
42 changes: 0 additions & 42 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/jit/namedintrinsiclist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -81,7 +81,7 @@ internal ref byte Value
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return ref _value.Value;
return ref _value;
}
}
}
Expand Down
14 changes: 0 additions & 14 deletions src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2298,11 +2298,6 @@ private int GatherClassGCLayout(TypeDesc type, byte* gcPtrs)
{
int result = 0;

if (type.IsByReferenceOfT)
{
return MarkGcField(gcPtrs, CorInfoGCType.TYPE_GC_BYREF);
}

foreach (var field in type.GetFields())
{
if (field.IsStatic)
Expand Down Expand Up @@ -2920,15 +2915,6 @@ private CorInfoType getFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STR
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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,21 +295,7 @@ private static bool ClassifyEightBytes(TypeDesc typeDesc,
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ private void MarkByRefAndORefLocations(MetadataType type, List<FieldLayoutInterv
{
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ public abstract partial class MetadataTypeSystemContext : TypeSystemContext
"Exception",

"TypedReference",
"ByReference`1",
};

public static IEnumerable<string> WellKnownTypeNames => s_wellKnownTypeNames;
Expand Down Expand Up @@ -71,7 +70,7 @@ public virtual void SetSystemModule(ModuleDesc systemModule)
// 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)
Expand All @@ -88,7 +87,7 @@ public override DefType GetWellKnownType(WellKnownType wellKnownType, bool throw

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;
Expand Down
13 changes: 0 additions & 13 deletions src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ internal void SetWellKnownType(WellKnownType wellKnownType)
case WellKnownType.RuntimeMethodHandle:
case WellKnownType.RuntimeFieldHandle:
case WellKnownType.TypedReference:
case WellKnownType.ByReferenceOfT:
flags = TypeFlags.ValueType;
break;

Expand Down Expand Up @@ -298,18 +297,6 @@ public bool IsNullable
}
}

/// <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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,5 @@ public enum WellKnownType
Exception,

TypedReference,
ByReferenceOfT,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,6 @@ internal static MarshallerKind GetMarshallerKind(
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
Expand All @@ -420,7 +419,6 @@ internal static MarshallerKind GetMarshallerKind(
// 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)
Expand Down
5 changes: 0 additions & 5 deletions src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,6 @@ public static bool IsSystemArgIterator(TypeSystemContext context, TypeDesc type)
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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,11 +372,6 @@ private void ImportCall(ILOpcode opcode, int token)
return;
}

if (method.OwningType.IsByReferenceOfT && (method.IsConstructor || method.Name == "get_Value"))
{
return;
}

if (IsEETypePtrOf(method))
{
if (runtimeDeterminedMethod.IsRuntimeDeterminedExactMethod)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

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).
Expand All @@ -35,7 +35,7 @@ public class GCRefMapBuilder
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;
Expand Down Expand Up @@ -293,7 +293,7 @@ private void GcScanValueType(TypeDesc type, ArgDestination argDest, int delta, C

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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ private void GetElementTypeInfoGeneric(
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ namespace IsByRefLike
{
public ref struct ByRefLikeStruct
{
ByReference<object> ByRef;
ref object ByRef;
}

public struct NotByRefLike
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public struct Double { }
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 { }
Expand All @@ -68,11 +68,9 @@ public class Exception { }

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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Loading