Skip to content

Commit

Permalink
Emission and reading of custom modifiers (#85504)
Browse files Browse the repository at this point in the history
Fixes #71883.

* Emit custom modifiers to the native metadata format
* Read custom modifiers at runtime
* Bugfix in the type loader
  • Loading branch information
MichalStrehovsky authored May 1, 2023
1 parent 9894fbf commit e56ff52
Showing 36 changed files with 512 additions and 95 deletions.
Original file line number Diff line number Diff line change
@@ -1649,7 +1649,7 @@ public MethodTable* this[int index]
if (((nint)_pFirst & IsRelative) != 0)
return (((RelativePointer<MethodTable>*)((nint)_pFirst - IsRelative)) + index)->Value;

return *(MethodTable**)_pFirst + index;
return *((MethodTable**)_pFirst + index);
}
#if TYPE_LOADER_IMPLEMENTATION
set
Original file line number Diff line number Diff line change
@@ -1,20 +1,123 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Reflection.Runtime.General;

using Internal.Metadata.NativeFormat;

using Debug = System.Diagnostics.Debug;

namespace System.Reflection
{
internal partial class ModifiedType
{
internal struct TypeSignature
internal readonly struct TypeSignature
{
internal readonly MetadataReader Reader;
internal readonly Handle Handle;
public TypeSignature(MetadataReader reader, Handle handle)
=> (Reader, Handle) = (reader, handle);
}

internal Type GetTypeParameter(Type unmodifiedType, int index)
{
MetadataReader reader = _typeSignature.Reader;
Handle handle = _typeSignature.Handle;

while (handle.HandleType == HandleType.ModifiedType)
handle = reader.GetModifiedType(handle.ToModifiedTypeHandle(reader)).Type;

if (handle.HandleType == HandleType.TypeSpecification)
handle = reader.GetTypeSpecification(handle.ToTypeSpecificationHandle(reader)).Signature;

switch (handle.HandleType)
{
case HandleType.SZArraySignature:
Debug.Assert(index == 0);
return Create(unmodifiedType, new TypeSignature(reader, reader.GetSZArraySignature(handle.ToSZArraySignatureHandle(reader)).ElementType));
case HandleType.ArraySignature:
Debug.Assert(index == 0);
return Create(unmodifiedType, new TypeSignature(reader, reader.GetArraySignature(handle.ToArraySignatureHandle(reader)).ElementType));
case HandleType.PointerSignature:
Debug.Assert(index == 0);
return Create(unmodifiedType, new TypeSignature(reader, reader.GetPointerSignature(handle.ToPointerSignatureHandle(reader)).Type));
case HandleType.ByReferenceSignature:
Debug.Assert(index == 0);
return Create(unmodifiedType, new TypeSignature(reader, reader.GetByReferenceSignature(handle.ToByReferenceSignatureHandle(reader)).Type));
case HandleType.FunctionPointerSignature:
{
MethodSignature functionSig = reader.GetMethodSignature(
reader.GetFunctionPointerSignature(handle.ToFunctionPointerSignatureHandle(reader)).Signature);
if (index-- == 0)
return Create(unmodifiedType, new TypeSignature(reader, functionSig.ReturnType));

Debug.Assert(index <= functionSig.Parameters.Count);
foreach (Handle paramHandle in functionSig.Parameters)
if (index-- == 0)
return Create(unmodifiedType, new TypeSignature(reader, paramHandle));
}
break;
case HandleType.TypeInstantiationSignature:
{
TypeInstantiationSignature typeInst =
reader.GetTypeInstantiationSignature(handle.ToTypeInstantiationSignatureHandle(reader));
Debug.Assert(index < typeInst.GenericTypeArguments.Count);
foreach (Handle paramHandle in typeInst.GenericTypeArguments)
if (index-- == 0)
return Create(unmodifiedType, new TypeSignature(reader, paramHandle));
}
break;
}

Debug.Fail(handle.HandleType.ToString());
return null;
}

internal SignatureCallingConvention GetCallingConventionFromFunctionPointer()
{
MetadataReader reader = _typeSignature.Reader;
Handle fnPtrTypeSigHandle = reader.GetTypeSpecification(
_typeSignature.Handle.ToTypeSpecificationHandle(reader)).Signature;
MethodSignatureHandle methodSigHandle = reader.GetFunctionPointerSignature(
fnPtrTypeSigHandle.ToFunctionPointerSignatureHandle(reader)).Signature;

Debug.Assert((int)Internal.Metadata.NativeFormat.SignatureCallingConvention.StdCall == (int)SignatureCallingConvention.StdCall);
Debug.Assert((int)Internal.Metadata.NativeFormat.SignatureCallingConvention.Unmanaged == (int)SignatureCallingConvention.Unmanaged);
return (SignatureCallingConvention)(reader.GetMethodSignature(methodSigHandle).CallingConvention
& Internal.Metadata.NativeFormat.SignatureCallingConvention.UnmanagedCallingConventionMask);
}

#pragma warning disable IDE0060
internal Type GetTypeParameter(Type unmodifiedType, int index) => throw new NotSupportedException();
private Type[] GetCustomModifiers(bool required)
{
ArrayBuilder<Type> builder = default;

MetadataReader reader = _typeSignature.Reader;
Handle handle = _typeSignature.Handle;

while (handle.HandleType == HandleType.ModifiedType)
{
var modifiedType = reader.GetModifiedType(handle.ToModifiedTypeHandle(reader));

internal SignatureCallingConvention GetCallingConventionFromFunctionPointer() => throw new NotSupportedException();
handle = modifiedType.Type;

if (modifiedType.IsOptional == required)
continue;

builder.Add(modifiedType.ModifierType.Resolve(reader, new TypeContext(null, null)));
}

Type[] result = builder.ToArray();

// We call Reverse for compat with CoreCLR that also reverses these.
// ILDasm also reverses these but don't be fooled: you can go to
// View -> MetaInfo -> Show to see the file format order in ILDasm.
Array.Reverse(result);

return result;
}

private Type[] GetCustomModifiers(bool required) => throw new NotSupportedException();
#pragma warning restore IDE0060
public static Type Create(Type unmodifiedType, MetadataReader reader, Handle typeSignature)
=> ModifiedType.Create(unmodifiedType, new TypeSignature(reader, typeSignature));
}
}
Original file line number Diff line number Diff line change
@@ -162,6 +162,8 @@ protected sealed override RuntimeTypeInfo FieldRuntimeType

protected sealed override int ExplicitLayoutFieldOffsetData => (int)(_field.Offset);

public sealed override Type GetModifiedFieldType() => ModifiedType.Create(FieldRuntimeType, _reader, FieldTypeHandle);

private Handle FieldTypeHandle => _field.Signature.GetFieldSignature(_reader).Type;

private readonly NativeFormatRuntimeNamedTypeInfo _definingTypeInfo;
Original file line number Diff line number Diff line change
@@ -61,5 +61,10 @@ internal Type[] GetCustomModifiers(TypeContext typeContext, bool optional)
return _handle.GetCustomModifiers((global::Internal.Metadata.NativeFormat.MetadataReader)Reader, typeContext, optional);
#endif
}

internal Type GetModifiedType(TypeContext typeContext)
{
return ModifiedType.Create(Resolve(typeContext), (global::Internal.Metadata.NativeFormat.MetadataReader)Reader, _handle);
}
}
}
Original file line number Diff line number Diff line change
@@ -36,6 +36,8 @@ public sealed override Type ParameterType
}
}

public sealed override Type GetModifiedParameterType() => QualifiedParameterTypeHandle.GetModifiedType(_typeContext);

protected readonly QSignatureTypeHandle QualifiedParameterTypeHandle;
private readonly TypeContext _typeContext;
private volatile Type _lazyParameterType;
Original file line number Diff line number Diff line change
@@ -75,6 +75,12 @@ public sealed override IEnumerable<CustomAttributeData> CustomAttributes
}
}

public override Type GetModifiedPropertyType()
{
return ModifiedType.Create(PropertyType, _reader, _reader.GetPropertySignature(_property.Signature).Type);

}

public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other)
{
ArgumentNullException.ThrowIfNull(other);
Original file line number Diff line number Diff line change
@@ -637,6 +637,24 @@ private static unsafe int CreateGCDesc(LowLevelList<bool> bitfield, int size, bo
return numSeries;
}

public static RuntimeTypeHandle CreateFunctionPointerEEType(uint hashCodeOfNewType, RuntimeTypeHandle returnTypeHandle, RuntimeTypeHandle[] parameterHandles, FunctionPointerType functionPointerType)
{
TypeBuilderState state = new TypeBuilderState(functionPointerType);

CreateEETypeWorker(typeof(delegate*<void>).TypeHandle.ToEETypePtr(), hashCodeOfNewType, 0, state);
Debug.Assert(!state.HalfBakedRuntimeTypeHandle.IsNull());

TypeLoaderLogger.WriteLine("Allocated new FUNCTION POINTER type " + functionPointerType.ToString() + " with hashcode value = 0x" + hashCodeOfNewType.LowLevelToString() + " with MethodTable = " + state.HalfBakedRuntimeTypeHandle.ToIntPtr().LowLevelToString());

state.HalfBakedRuntimeTypeHandle.ToEETypePtr()->FunctionPointerReturnType = returnTypeHandle.ToEETypePtr();
Debug.Assert(state.HalfBakedRuntimeTypeHandle.ToEETypePtr()->NumFunctionPointerParameters == parameterHandles.Length);
MethodTableList paramList = state.HalfBakedRuntimeTypeHandle.ToEETypePtr()->FunctionPointerParameters;
for (int i = 0; i < parameterHandles.Length; i++)
paramList[i] = parameterHandles[i].ToEETypePtr();

return state.HalfBakedRuntimeTypeHandle;
}

public static RuntimeTypeHandle CreatePointerEEType(uint hashCodeOfNewType, RuntimeTypeHandle pointeeTypeHandle, TypeDesc pointerType)
{
TypeBuilderState state = new TypeBuilderState(pointerType);
Original file line number Diff line number Diff line change
@@ -1304,6 +1304,30 @@ public static bool TryBuildByRefType(RuntimeTypeHandle pointeeTypeHandle, out Ru
return true;
}

public static bool TryBuildFunctionPointerType(RuntimeTypeHandle returnTypeHandle, RuntimeTypeHandle[] parameterHandles, bool isUnmanaged, out RuntimeTypeHandle runtimeTypeHandle)
{
var key = new TypeSystemContext.FunctionPointerTypeKey(returnTypeHandle, parameterHandles, isUnmanaged);
if (!TypeSystemContext.FunctionPointerTypesCache.TryGetValue(key, out runtimeTypeHandle))
{
TypeSystemContext context = TypeSystemContextFactory.Create();
FunctionPointerType functionPointerType = context.GetFunctionPointerType(new MethodSignature(
isUnmanaged ? MethodSignatureFlags.UnmanagedCallingConvention : 0,
genericParameterCount: 0,
context.ResolveRuntimeTypeHandle(returnTypeHandle),
context.ResolveRuntimeTypeHandlesInternal(parameterHandles)));
runtimeTypeHandle = EETypeCreator.CreateFunctionPointerEEType((uint)functionPointerType.GetHashCode(), returnTypeHandle, parameterHandles, functionPointerType);
unsafe
{
Debug.Assert(runtimeTypeHandle.ToEETypePtr()->IsFunctionPointerType);
}
TypeSystemContext.FunctionPointerTypesCache.AddOrGetExisting(runtimeTypeHandle);

// Recycle the context only if we successfully built the type. The state may be partially initialized otherwise.
TypeSystemContextFactory.Recycle(context);
}
return true;
}

internal static bool TryBuildGenericMethod(InstantiatedMethod methodBeingLoaded, out IntPtr methodDictionary)
{
try
Original file line number Diff line number Diff line change
@@ -349,15 +349,33 @@ public bool TryGetFunctionPointerTypeForComponents(RuntimeTypeHandle returnTypeH

using (LockHolder.Hold(_typeLoaderLock))
{
throw new NotImplementedException();
return TypeBuilder.TryBuildFunctionPointerType(returnTypeHandle, parameterHandles, isUnmanaged, out runtimeTypeHandle);
}
}

public bool TryLookupFunctionPointerTypeForComponents(RuntimeTypeHandle returnTypeHandle, RuntimeTypeHandle[] parameterHandles, bool isUnmanaged, out RuntimeTypeHandle runtimeTypeHandle)
{
// TODO: cache same as for arrays
// TODO: lookup dynamically built ones
return TryGetStaticFunctionPointerTypeForComponents(returnTypeHandle, parameterHandles, isUnmanaged, out runtimeTypeHandle);
var key = new TypeSystemContext.FunctionPointerTypeKey(returnTypeHandle, parameterHandles, isUnmanaged);
if (TypeSystemContext.FunctionPointerTypesCache.TryGetValue(key, out runtimeTypeHandle))
return true;

if (!RuntimeAugments.IsDynamicType(returnTypeHandle)
&& AllNonDynamicTypes(parameterHandles)
&& TryGetStaticFunctionPointerTypeForComponents(returnTypeHandle, parameterHandles, isUnmanaged, out runtimeTypeHandle))
{
TypeSystemContext.FunctionPointerTypesCache.AddOrGetExisting(runtimeTypeHandle);
return true;
}

return false;

static bool AllNonDynamicTypes(RuntimeTypeHandle[] handles)
{
foreach (RuntimeTypeHandle h in handles)
if (RuntimeAugments.IsDynamicType(h))
return false;
return true;
}
}

// Get an array RuntimeTypeHandle given an element's RuntimeTypeHandle and rank. Pass false for isMdArray, and rank == -1 for SzArrays
Original file line number Diff line number Diff line change
@@ -162,7 +162,7 @@ internal static RuntimeTypeHandleToParameterTypeRuntimeTypeHandleHashtable GetAr
internal static FunctionPointerRuntimeTypeHandleHashtable FunctionPointerTypesCache { get; }
= new FunctionPointerRuntimeTypeHandleHashtable();

private TypeDesc[] ResolveRuntimeTypeHandlesInternal(RuntimeTypeHandle[] runtimeTypeHandles)
public TypeDesc[] ResolveRuntimeTypeHandlesInternal(RuntimeTypeHandle[] runtimeTypeHandles)
{
TypeDesc[] TypeDescs = new TypeDesc[runtimeTypeHandles.Length];
for (int i = 0; i < runtimeTypeHandles.Length; i++)
Original file line number Diff line number Diff line change
@@ -558,7 +558,7 @@ from primitiveType in PrimitiveTypes select
name: "MethodInstantiation",
members: new MemberDef[] {
new MemberDef("Method", MethodDefOrRef, MemberDefFlags.RecordRef),
new MemberDef("GenericTypeArguments", TypeDefOrRefOrSpec, MemberDefFlags.List | MemberDefFlags.RecordRef),
new MemberDef("GenericTypeArguments", TypeDefOrRefOrSpecOrMod, MemberDefFlags.List | MemberDefFlags.RecordRef),
// COMPLETENESS: new MemberDef("CustomAttributes", "CustomAttribute", MemberDefFlags.List | MemberDefFlags.RecordRef | MemberDefFlags.Child),
}
),
@@ -674,7 +674,7 @@ from primitiveType in PrimitiveTypes select
name: "TypeInstantiationSignature",
members: new MemberDef[] {
new MemberDef("GenericType", TypeDefOrRefOrSpec, MemberDefFlags.RecordRef),
new MemberDef("GenericTypeArguments", TypeDefOrRefOrSpec, MemberDefFlags.List | MemberDefFlags.RecordRef),
new MemberDef("GenericTypeArguments", TypeDefOrRefOrSpecOrMod, MemberDefFlags.List | MemberDefFlags.RecordRef),
}
),
new RecordDef(
@@ -686,7 +686,7 @@ from primitiveType in PrimitiveTypes select
new RecordDef(
name: "ArraySignature",
members: new MemberDef[] {
new MemberDef("ElementType", TypeDefOrRefOrSpec, MemberDefFlags.RecordRef),
new MemberDef("ElementType", TypeDefOrRefOrSpecOrMod, MemberDefFlags.RecordRef),
new MemberDef("Rank", "int"),
new MemberDef("Sizes", "Int32", MemberDefFlags.Array),
new MemberDef("LowerBounds", "Int32", MemberDefFlags.Array),
@@ -695,7 +695,7 @@ from primitiveType in PrimitiveTypes select
new RecordDef(
name: "ByReferenceSignature",
members: new MemberDef[] {
new MemberDef("Type", TypeDefOrRefOrSpec, MemberDefFlags.RecordRef),
new MemberDef("Type", TypeDefOrRefOrSpecOrMod, MemberDefFlags.RecordRef),
}
),
new RecordDef(
Original file line number Diff line number Diff line change
@@ -37,7 +37,7 @@ public ArraySignatureHandle Handle
return _handle;
}
} // Handle
/// One of: TypeDefinition, TypeReference, TypeSpecification
/// One of: TypeDefinition, TypeReference, TypeSpecification, ModifiedType

public Handle ElementType
{
@@ -182,7 +182,7 @@ public ByReferenceSignatureHandle Handle
return _handle;
}
} // Handle
/// One of: TypeDefinition, TypeReference, TypeSpecification
/// One of: TypeDefinition, TypeReference, TypeSpecification, ModifiedType

public Handle Type
{
@@ -4901,7 +4901,7 @@ public Handle Method
} // Method

internal Handle _method;
/// One of: TypeDefinition, TypeReference, TypeSpecification
/// One of: TypeDefinition, TypeReference, TypeSpecification, ModifiedType

public HandleCollection GenericTypeArguments
{
@@ -7756,7 +7756,7 @@ public Handle GenericType
} // GenericType

internal Handle _genericType;
/// One of: TypeDefinition, TypeReference, TypeSpecification
/// One of: TypeDefinition, TypeReference, TypeSpecification, ModifiedType

public HandleCollection GenericTypeArguments
{
2 changes: 2 additions & 0 deletions src/coreclr/tools/Common/TypeSystem/Common/FieldDesc.cs
Original file line number Diff line number Diff line change
@@ -47,6 +47,8 @@ public abstract TypeDesc FieldType
// Get the embedded signature data used to hold custom modifiers and such within a field signature
public abstract EmbeddedSignatureData[] GetEmbeddedSignatureData();

public abstract bool HasEmbeddedSignatureData { get; }

public abstract bool IsStatic
{
get;
Original file line number Diff line number Diff line change
@@ -54,6 +54,14 @@ public override EmbeddedSignatureData[] GetEmbeddedSignatureData()
return _fieldDef.GetEmbeddedSignatureData();
}

public override bool HasEmbeddedSignatureData
{
get
{
return _fieldDef.HasEmbeddedSignatureData;
}
}

public override bool IsStatic
{
get
Loading

0 comments on commit e56ff52

Please sign in to comment.