Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Commit

Permalink
Implement TypedReference in CoreRT (#3000)
Browse files Browse the repository at this point in the history
This is basically three things:

1. `ByReference<T>` support
2. General support infra in the type system for Byref-like types (to be
reused for e.g. `Span<T>`).
3. TypedReference

Fixes #367.
  • Loading branch information
MichalStrehovsky committed Mar 23, 2017
1 parent 2c7f590 commit f4407ca
Show file tree
Hide file tree
Showing 33 changed files with 438 additions and 26 deletions.
5 changes: 5 additions & 0 deletions src/Common/src/Internal/Runtime/EEType.Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ internal enum EETypeRareFlags : int
/// This EEType is an abstract class (but not an interface).
/// </summary>
IsAbstractClassFlag = 0x00004000,

/// <summary>
/// This EEType is for a Byref-like class (TypedReference, Span&lt;T&gt;,...)
/// </summary>
IsByRefLikeFlag = 0x00008000,
}

internal enum EETypeField
Expand Down
8 changes: 8 additions & 0 deletions src/Common/src/Internal/Runtime/EEType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,14 @@ internal bool IsAbstract
}
}

internal bool IsByRefLike
{
get
{
return (RareFlags & EETypeRareFlags.IsByRefLikeFlag) != 0;
}
}

internal bool IsDynamicType
{
get
Expand Down
41 changes: 41 additions & 0 deletions src/Common/src/TypeSystem/Common/DefType.FieldLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ private class FieldLayoutFlags
/// True if information about the shape of value type has been computed.
/// </summary>
public const int ComputedValueTypeShapeCharacteristics = 0x40;

/// <summary>
/// True if <see cref="IsByRefLike"/> has been computed.
/// </summary>
public const int ComputedIsByRefLike = 0x80;

/// <summary>
/// True if this is a byref-like type.
/// </summary>
public const int IsByRefLike = 0x100;
}

private class StaticBlockInfo
Expand Down Expand Up @@ -275,6 +285,22 @@ public DefType HfaElementType
}
}

/// <summary>
/// Gets a value indicating whether this is a byref-like type
/// (a <code>TypedReference</code>, <code>Span&lt;T&gt;</code>, etc.).
/// </summary>
public bool IsByRefLike
{
get
{
if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedIsByRefLike))
{
ComputeIsByRefLike();
}
return _fieldLayoutFlags.HasFlags(FieldLayoutFlags.IsByRefLike);
}
}

private void ComputeValueTypeShapeCharacteristics()
{
_valueTypeShapeCharacteristics = this.Context.GetLayoutAlgorithmForType(this).ComputeValueTypeShapeCharacteristics(this);
Expand Down Expand Up @@ -360,6 +386,21 @@ public void ComputeTypeContainsGCPointers()

_fieldLayoutFlags.AddFlags(flagsToAdd);
}

public void ComputeIsByRefLike()
{
if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedIsByRefLike))
return;

int flagsToAdd = FieldLayoutFlags.ComputedIsByRefLike;

if (this.Context.GetLayoutAlgorithmForType(this).ComputeIsByRefLike(this))
{
flagsToAdd |= FieldLayoutFlags.IsByRefLike;
}

_fieldLayoutFlags.AddFlags(flagsToAdd);
}
}

}
5 changes: 5 additions & 0 deletions src/Common/src/TypeSystem/Common/FieldLayoutAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public abstract class FieldLayoutAlgorithm
/// the element type of the homogenous float aggregate. This will either be System.Double or System.Float.
/// </summary>
public abstract DefType ComputeHomogeneousFloatAggregateElementType(DefType type);

/// <summary>
/// Compute whether '<paramref name="type"/>' is a ByRef-like value type (TypedReference, Span&lt;T&gt;, etc.).
/// </summary>
public abstract bool ComputeIsByRefLike(DefType type);
}

/// <summary>
Expand Down
66 changes: 56 additions & 10 deletions src/Common/src/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,25 @@ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType defTyp
// Count the number of instance fields in advance for convenience
int numInstanceFields = 0;
foreach (var field in type.GetFields())
if (!field.IsStatic)
numInstanceFields++;
{
if (field.IsStatic)
continue;

TypeDesc fieldType = field.FieldType;

// ByRef instance fields are not allowed.
if (fieldType.IsByRef)
throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);

// ByRef-like instance fields on reference types are not allowed.
if (fieldType.IsValueType && !type.IsValueType)
{
if (((DefType)fieldType).IsByRefLike)
throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
}

numInstanceFields++;
}

if (type.IsModuleType)
{
Expand Down Expand Up @@ -123,11 +140,6 @@ out instanceByteSizeAndAlignment
return result;
}

// Verify that no ByRef types present in this type's fields
foreach (var field in type.GetFields())
if (field.FieldType.IsByRef)
throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);

// If the type has layout, read its packing and size info
// If the type has explicit layout, also read the field offset info
if (type.IsExplicitLayout || type.IsSequentialLayout)
Expand Down Expand Up @@ -198,12 +210,18 @@ public unsafe override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefTyp
if (!field.IsStatic || field.HasRva || field.IsLiteral)
continue;

TypeDesc fieldType = field.FieldType;
if (fieldType.IsByRef || (fieldType.IsValueType && ((DefType)fieldType).IsByRefLike))
{
throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
}

StaticsBlock* block =
field.IsThreadStatic ? &result.ThreadStatics :
field.HasGCStaticBase ? &result.GcStatics :
&result.NonGcStatics;

SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, type.Context.Target.DefaultPackingSize);
SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, type.Context.Target.DefaultPackingSize);

block->Size = LayoutInt.AlignUp(block->Size, sizeAndAlignment.Alignment);
result.Offsets[index] = new FieldAndOffset(field, block->Size);
Expand Down Expand Up @@ -240,7 +258,7 @@ public override bool ComputeContainsGCPointers(DefType type)
break;
}
}
else if (fieldType.IsGCPointer || fieldType.IsByRef)
else if (fieldType.IsGCPointer)
{
someFieldContainsPointers = true;
break;
Expand Down Expand Up @@ -403,7 +421,7 @@ private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType,
result.Alignment = fieldType.Context.Target.LayoutPointerSize;
}
}
else if (fieldType.IsByRef || fieldType.IsArray)
else if (fieldType.IsArray)
{
// This could use InstanceFieldSize/Alignment (and those results should match what's here)
// but, its more efficient to just assume pointer size instead of fulling processing
Expand Down Expand Up @@ -601,6 +619,34 @@ public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type
}
}

public override bool ComputeIsByRefLike(DefType type)
{
// Reference types can never be ByRef-like.
if (!type.IsValueType)
return false;

if (type.IsByReferenceOfT)
return true;

foreach (FieldDesc field in type.GetFields())
{
if (field.IsStatic)
continue;

TypeDesc fieldType = field.FieldType;
if (fieldType.IsValueType && !fieldType.IsPrimitive)
{
DefType fieldDefType = (DefType)fieldType;
if (fieldDefType.IsByRefLike)
{
return true;
}
}
}

return false;
}

private struct SizeAndAlignment
{
public LayoutInt Size;
Expand Down
3 changes: 3 additions & 0 deletions src/Common/src/TypeSystem/Common/MetadataTypeSystemContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public abstract partial class MetadataTypeSystemContext : TypeSystemContext
"RuntimeFieldHandle",

"Exception",

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

private MetadataType[] _wellKnownTypes;
Expand Down
14 changes: 14 additions & 0 deletions src/Common/src/TypeSystem/Common/TypeDesc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ internal void SetWellKnownType(WellKnownType wellKnownType)
case WellKnownType.RuntimeTypeHandle:
case WellKnownType.RuntimeMethodHandle:
case WellKnownType.RuntimeFieldHandle:
case WellKnownType.TypedReference:
case WellKnownType.ByReferenceOfT:
flags = TypeFlags.ValueType;
break;

Expand Down Expand Up @@ -265,6 +267,18 @@ 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 @@ -19,7 +19,12 @@ public class UniversalCanonLayoutAlgorithm : FieldLayoutAlgorithm
public override bool ComputeContainsGCPointers(DefType type)
{
// This should never be called
throw new ArgumentException();
throw new NotSupportedException();
}

public override bool ComputeIsByRefLike(DefType type)
{
return false;
}

public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type)
Expand Down
3 changes: 3 additions & 0 deletions src/Common/src/TypeSystem/Common/WellKnownType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,8 @@ public enum WellKnownType
RuntimeFieldHandle,

Exception,

TypedReference,
ByReferenceOfT,
}
}
2 changes: 1 addition & 1 deletion src/Common/src/TypeSystem/Ecma/EcmaSignatureParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ private TypeDesc ParseType(SignatureTypeCode typeCode)
return _module.Context.GetInstantiatedType(metadataTypeDef, new Instantiation(instance));
}
case SignatureTypeCode.TypedReference:
throw new PlatformNotSupportedException("TypedReference not supported in .NET Core");
return GetWellKnownType(WellKnownType.TypedReference);
case SignatureTypeCode.FunctionPointer:
return _module.Context.GetFunctionPointerType(ParseMethodSignature());
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ public static bool CreationAllowed(TypeDesc type)
if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any))
return false;

// Byref-like types have interior pointers and cannot be heap allocated.
if (type.IsValueType && ((DefType)type).IsByRefLike)
return false;

break;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,8 @@ void ComputeRareFlags(NodeFactory factory)
{
uint flags = 0;

MetadataType metadataType = _type as MetadataType;

if (_type.IsNullable)
{
flags |= (uint)EETypeRareFlags.IsNullableFlag;
Expand All @@ -537,7 +539,7 @@ void ComputeRareFlags(NodeFactory factory)
flags |= (uint)EETypeRareFlags.RequiresAlign8Flag;
}

if (_type.IsDefType && ((DefType)_type).IsHfa)
if (metadataType != null && metadataType.IsHfa)
{
flags |= (uint)EETypeRareFlags.IsHFAFlag;
}
Expand All @@ -551,11 +553,16 @@ void ComputeRareFlags(NodeFactory factory)
}
}

if ((_type is MetadataType) && !_type.IsInterface && ((MetadataType)_type).IsAbstract)
if (metadataType != null && !_type.IsInterface && metadataType.IsAbstract)
{
flags |= (uint)EETypeRareFlags.IsAbstractClassFlag;
}

if (metadataType != null && metadataType.IsByRefLike)
{
flags |= (uint)EETypeRareFlags.IsByRefLikeFlag;
}

if (flags != 0)
{
_optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldTag.RareFlags, flags);
Expand Down Expand Up @@ -699,7 +706,11 @@ public static void CheckCanGenerateEEType(NodeFactory factory, TypeDesc type)
foreach (TypeDesc typeArg in defType.Instantiation)
{
// ByRefs, pointers, function pointers, and System.Void are never valid instantiation arguments
if (typeArg.IsByRef || typeArg.IsPointer || typeArg.IsFunctionPointer || typeArg.IsVoid)
if (typeArg.IsByRef
|| typeArg.IsPointer
|| typeArg.IsFunctionPointer
|| typeArg.IsVoid
|| (typeArg.IsValueType && ((DefType)typeArg).IsByRefLike))
{
throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
}
Expand Down Expand Up @@ -739,6 +750,12 @@ public static void CheckCanGenerateEEType(NodeFactory factory, TypeDesc type)
{
throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadRankTooLarge, type);
}

if ((parameterType.IsDefType) && ((DefType)parameterType).IsByRefLike)
{
// Arrays of byref-like types are not allowed
throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
}
}

// Validate we're not constructing a type over a ByRef
Expand Down
7 changes: 7 additions & 0 deletions src/ILCompiler.Compiler/src/Compiler/JitHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id,
methodDesc = context.SystemModule.GetKnownType("System.Runtime", "TypeLoaderExports").GetKnownMethod("GVMLookupForSlot", null);
break;

case ReadyToRunHelper.TypeHandleToRuntimeType:
methodDesc = context.GetHelperEntryPoint("TypedReferenceHelpers", "TypeHandleToRuntimeTypeMaybeNull");
break;
case ReadyToRunHelper.GetRefAny:
methodDesc = context.GetHelperEntryPoint("TypedReferenceHelpers", "GetRefAny");
break;

default:
throw new NotImplementedException(id.ToString());
}
Expand Down
Loading

0 comments on commit f4407ca

Please sign in to comment.