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
Show file tree
Hide file tree
Showing 36 changed files with 512 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
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
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
),
Expand Down Expand Up @@ -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(
Expand All @@ -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),
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public ArraySignatureHandle Handle
return _handle;
}
} // Handle
/// One of: TypeDefinition, TypeReference, TypeSpecification
/// One of: TypeDefinition, TypeReference, TypeSpecification, ModifiedType

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

public Handle Type
{
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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
{
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/tools/Common/TypeSystem/Common/FieldDesc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ public override EmbeddedSignatureData[] GetEmbeddedSignatureData()
return _fieldDef.GetEmbeddedSignatureData();
}

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

public override bool IsStatic
{
get
Expand Down
Loading

0 comments on commit e56ff52

Please sign in to comment.