| File: Internal\Runtime\TypeLoader\GenericDictionaryCell.cs | Web Access |
| Project: src\runtime\src\coreclr\nativeaot\System.Private.TypeLoader\src\System.Private.TypeLoader.csproj (System.Private.TypeLoader) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics; using System.Runtime; using Internal.Metadata.NativeFormat; using Internal.NativeFormat; using Internal.Runtime.Augments; using Internal.Runtime.CompilerServices; using Internal.TypeSystem; using Internal.TypeSystem.NoMetadata; namespace Internal.Runtime.TypeLoader { public abstract class GenericDictionaryCell { internal abstract void Prepare(TypeBuilder builder); internal abstract IntPtr Create(TypeBuilder builder); internal virtual unsafe void WriteCellIntoDictionary(TypeBuilder typeBuilder, IntPtr* pDictionary, int slotIndex) { pDictionary[slotIndex] = Create(typeBuilder); } internal virtual IntPtr CreateLazyLookupCell(TypeBuilder builder, out IntPtr auxResult) { auxResult = IntPtr.Zero; return Create(builder); } // Helper method for nullable transform. Ideally, we would do the nullable transform upfront before // the types is build. Unfortunately, there does not seem to be easy way to test for Nullable<> type definition // without introducing type builder recursion private static RuntimeTypeHandle GetRuntimeTypeHandleWithNullableTransform(TypeBuilder builder, TypeDesc type) { RuntimeTypeHandle th = builder.GetRuntimeTypeHandle(type); if (RuntimeAugments.IsNullable(th)) th = builder.GetRuntimeTypeHandle(((DefType)type).Instantiation[0]); return th; } private class TypeHandleCell : GenericDictionaryCell { internal TypeDesc Type; internal override void Prepare(TypeBuilder builder) { if (Type.IsCanonicalSubtype(CanonicalFormKind.Any)) Environment.FailFast("Canonical types do not have EETypes"); builder.RegisterForPreparation(Type); } internal override IntPtr Create(TypeBuilder builder) { return builder.GetRuntimeTypeHandle(Type).ToIntPtr(); } } private class UnwrapNullableTypeCell : GenericDictionaryCell { internal DefType Type; internal override void Prepare(TypeBuilder builder) { if (Type.IsCanonicalSubtype(CanonicalFormKind.Any)) Environment.FailFast("Canonical types do not have EETypes"); if (Type.IsNullable) { Debug.Assert(Type.Instantiation.Length == 1); builder.RegisterForPreparation(Type.Instantiation[0]); } else builder.RegisterForPreparation(Type); } internal override IntPtr Create(TypeBuilder builder) { if (Type.IsNullable) return builder.GetRuntimeTypeHandle(Type.Instantiation[0]).ToIntPtr(); else return builder.GetRuntimeTypeHandle(Type).ToIntPtr(); } } private class InterfaceCallCell : GenericDictionaryCell { internal TypeDesc InterfaceType; internal int Slot; internal override void Prepare(TypeBuilder builder) { if (InterfaceType.IsCanonicalSubtype(CanonicalFormKind.Any)) Environment.FailFast("Unable to compute call information for a canonical interface"); builder.RegisterForPreparation(InterfaceType); } internal override unsafe IntPtr Create(TypeBuilder builder) { var dispatchCell = (DynamicDispatchCell.DynamicInterfaceDispatchCell*)MemoryHelpers.AllocateMemory(sizeof(DynamicDispatchCell.DynamicInterfaceDispatchCell)); dispatchCell->DispatchCell.Cell = default; dispatchCell->InterfaceType = builder.GetRuntimeTypeHandle(InterfaceType).ToIntPtr(); dispatchCell->Slot = Slot; return (IntPtr)dispatchCell; } } private class GvmDispatchCell : GenericDictionaryCell { internal MethodDesc Method; internal override void Prepare(TypeBuilder builder) { if (Method.IsCanonicalMethod(CanonicalFormKind.Any)) Environment.FailFast("Unable to compute GVM dispatch information for a canonical method."); builder.RegisterForPreparation(Method.OwningType); foreach (var type in Method.Instantiation) builder.RegisterForPreparation(type); } internal override unsafe IntPtr Create(TypeBuilder builder) { var dispatchCell = (DynamicDispatchCell.DynamicGvmDispatchCell*)MemoryHelpers.AllocateMemory(sizeof(DynamicDispatchCell.DynamicGvmDispatchCell)); dispatchCell->DispatchCell.Cell = default; dispatchCell->OwningType = builder.GetRuntimeTypeHandle(Method.OwningType).ToIntPtr(); dispatchCell->Handle = Method.NameAndSignature.Handle; dispatchCell->IsAsyncVariant = Method.AsyncVariant; MethodTable** instantiation = (MethodTable**)MemoryHelpers.AllocateMemory(sizeof(MethodTable*) * Method.Instantiation.Length); for (int i = 0; i < Method.Instantiation.Length; i++) { instantiation[i] = (MethodTable*)builder.GetRuntimeTypeHandle(Method.Instantiation[i]).Value; } dispatchCell->Instantiation = instantiation; return (IntPtr)dispatchCell; } } /// <summary> /// Used for non-generic static constrained Methods /// </summary> private class NonGenericStaticConstrainedMethodCell : GenericDictionaryCell { internal TypeDesc ConstraintType; internal TypeDesc ConstrainedMethodType; internal int ConstrainedMethodSlot; internal override void Prepare(TypeBuilder builder) { if (ConstraintType.IsCanonicalSubtype(CanonicalFormKind.Any) || ConstrainedMethodType.IsCanonicalSubtype(CanonicalFormKind.Any)) Environment.FailFast("Unable to compute call information for a canonical type/method."); builder.RegisterForPreparation(ConstraintType); builder.RegisterForPreparation(ConstrainedMethodType); } internal override IntPtr Create(TypeBuilder builder) { IntPtr result = RuntimeAugments.ResolveStaticDispatchOnType( builder.GetRuntimeTypeHandle(ConstraintType), builder.GetRuntimeTypeHandle(ConstrainedMethodType), ConstrainedMethodSlot, out RuntimeTypeHandle genericContext); Debug.Assert(result != IntPtr.Zero); if (!genericContext.IsNull()) { result = FunctionPointerOps.GetGenericMethodFunctionPointer(result, genericContext.ToIntPtr()); } return result; } } /// <summary> /// Used for non-generic instance constrained Methods /// </summary> private class NonGenericInstanceConstrainedMethodCell : GenericDictionaryCell { internal TypeDesc ConstraintType; internal TypeDesc ConstrainedMethodType; internal int ConstrainedMethodSlot; internal override void Prepare(TypeBuilder builder) { if (ConstraintType.IsCanonicalSubtype(CanonicalFormKind.Any) || ConstrainedMethodType.IsCanonicalSubtype(CanonicalFormKind.Any)) Environment.FailFast("Unable to compute call information for a canonical type/method."); builder.RegisterForPreparation(ConstraintType); builder.RegisterForPreparation(ConstrainedMethodType); } internal override IntPtr Create(TypeBuilder builder) { IntPtr result = RuntimeAugments.ResolveDispatchOnType( builder.GetRuntimeTypeHandle(ConstraintType), builder.GetRuntimeTypeHandle(ConstrainedMethodType), ConstrainedMethodSlot); Debug.Assert(result != IntPtr.Zero); return result; } } /// <summary> /// Used for generic static constrained Methods /// </summary> private class GenericConstrainedMethodCell : GenericDictionaryCell { internal DefType ConstraintType; internal InstantiatedMethod ConstrainedMethod; private InstantiatedMethod _resolvedMethod; internal override void Prepare(TypeBuilder builder) { _resolvedMethod = TypeLoaderEnvironment.GVMLookupForSlotWorker(ConstraintType, ConstrainedMethod); if (_resolvedMethod.CanShareNormalGenericCode()) builder.PrepareMethod(_resolvedMethod); } internal override IntPtr Create(TypeBuilder builder) { if (_resolvedMethod.CanShareNormalGenericCode()) { IntPtr methodDictionary = _resolvedMethod.RuntimeMethodDictionary; return FunctionPointerOps.GetGenericMethodFunctionPointer(_resolvedMethod.FunctionPointer, methodDictionary); } else { if (!TypeLoaderEnvironment.Instance.TryLookupExactMethodPointer(_resolvedMethod, out nint result)) Environment.FailFast("Unable to find exact method pointer for a resolved GVM."); return result; } } } private class StaticDataCell : GenericDictionaryCell { internal StaticDataKind DataKind; internal TypeDesc Type; internal override void Prepare(TypeBuilder builder) { if (Type.IsCanonicalSubtype(CanonicalFormKind.Any)) Environment.FailFast("Unable to compute static field locations for a canonical type."); builder.RegisterForPreparation(Type); } internal override IntPtr Create(TypeBuilder builder) { RuntimeTypeHandle typeHandle = builder.GetRuntimeTypeHandle(Type); switch (DataKind) { case StaticDataKind.NonGc: return TypeLoaderEnvironment.Instance.TryGetNonGcStaticFieldData(typeHandle); case StaticDataKind.Gc: return TypeLoaderEnvironment.Instance.TryGetGcStaticFieldData(typeHandle); default: Debug.Assert(false); return IntPtr.Zero; } } internal override unsafe IntPtr CreateLazyLookupCell(TypeBuilder builder, out IntPtr auxResult) { auxResult = IntPtr.Zero; return *(IntPtr*)Create(builder); } } private class ThreadStaticIndexCell : GenericDictionaryCell { internal TypeDesc Type; internal override void Prepare(TypeBuilder builder) { if (Type.IsCanonicalSubtype(CanonicalFormKind.Any)) Environment.FailFast("Unable to compute static field locations for a canonical type."); builder.RegisterForPreparation(Type); } internal override unsafe IntPtr Create(TypeBuilder builder) { return TypeLoaderEnvironment.Instance.TryGetThreadStaticFieldData(builder.GetRuntimeTypeHandle(Type)); } } private class MethodDictionaryCell : GenericDictionaryCell { internal InstantiatedMethod GenericMethod; internal override unsafe void Prepare(TypeBuilder builder) { if (GenericMethod.IsCanonicalMethod(CanonicalFormKind.Any)) Environment.FailFast("Method dictionaries of canonical methods do not exist"); builder.PrepareMethod(GenericMethod); } internal override IntPtr Create(TypeBuilder builder) { Debug.Assert(GenericMethod.RuntimeMethodDictionary != IntPtr.Zero); return GenericMethod.RuntimeMethodDictionary; } } private class FieldLdTokenCell : GenericDictionaryCell { internal TypeDesc ContainingType; internal int FieldHandle; internal override unsafe void Prepare(TypeBuilder builder) { if (ContainingType.IsCanonicalSubtype(CanonicalFormKind.Any)) Environment.FailFast("Ldtoken is not permitted for a canonical field"); builder.RegisterForPreparation(ContainingType); } internal override unsafe IntPtr Create(TypeBuilder builder) { RuntimeFieldHandle handle = TypeLoaderEnvironment.Instance.GetRuntimeFieldHandleForComponents( builder.GetRuntimeTypeHandle(ContainingType), FieldHandle); return *(IntPtr*)&handle; } } private class MethodLdTokenCell : GenericDictionaryCell { internal MethodDesc Method; internal override unsafe void Prepare(TypeBuilder builder) { if (Method.IsCanonicalMethod(CanonicalFormKind.Any)) Environment.FailFast("Ldtoken is not permitted for a canonical method"); // Do not use builder.PrepareMethod here. That // would prepare the dictionary for the method, // and if the method is abstract, there is no // dictionary. Also, the dictionary is not necessary // to create the ldtoken. builder.RegisterForPreparation(Method.OwningType); foreach (var type in Method.Instantiation) builder.RegisterForPreparation(type); } internal override unsafe IntPtr Create(TypeBuilder builder) { RuntimeTypeHandle[] genericArgHandles = Method.HasInstantiation && !Method.IsMethodDefinition ? builder.GetRuntimeTypeHandles(Method.Instantiation) : null; RuntimeMethodHandle handle = TypeLoaderEnvironment.Instance.GetRuntimeMethodHandleForComponents( builder.GetRuntimeTypeHandle(Method.OwningType), Method.NameAndSignature.Handle, genericArgHandles); return *(IntPtr*)&handle; } } private class AllocateObjectCell : GenericDictionaryCell { internal TypeDesc Type; internal override void Prepare(TypeBuilder builder) { if (Type.IsCanonicalSubtype(CanonicalFormKind.Any)) Environment.FailFast("Canonical types cannot be allocated"); builder.RegisterForPreparation(Type); } internal override IntPtr Create(TypeBuilder builder) { RuntimeTypeHandle th = GetRuntimeTypeHandleWithNullableTransform(builder, Type); return RuntimeAugments.GetAllocateObjectHelperForType(th); } internal override unsafe IntPtr CreateLazyLookupCell(TypeBuilder builder, out IntPtr auxResult) { RuntimeTypeHandle th = GetRuntimeTypeHandleWithNullableTransform(builder, Type); auxResult = th.ToIntPtr(); return RuntimeAugments.GetAllocateObjectHelperForType(th); } } private class DefaultConstructorCell : GenericDictionaryCell { internal TypeDesc Type; internal override void Prepare(TypeBuilder builder) { builder.RegisterForPreparation(Type); } internal override IntPtr Create(TypeBuilder builder) { IntPtr result = TypeLoaderEnvironment.TryGetDefaultConstructorForType(Type); if (result != IntPtr.Zero) { if (Type.IsValueType) { result = TypeLoaderEnvironment.ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(result, builder.GetRuntimeTypeHandle(Type)); } } else { result = RuntimeAugments.GetFallbackDefaultConstructor(); } return result; } } private class MethodCell : GenericDictionaryCell { internal MethodDesc Method; internal override unsafe void Prepare(TypeBuilder builder) { builder.PrepareMethod(Method); } internal override unsafe IntPtr Create(TypeBuilder builder) { IntPtr methodDictionary = Method.Instantiation.Length > 0 ? ((InstantiatedMethod)Method).RuntimeMethodDictionary : builder.GetRuntimeTypeHandle(Method.OwningType).ToIntPtr(); return FunctionPointerOps.GetGenericMethodFunctionPointer(Method.FunctionPointer, methodDictionary); } } internal static unsafe GenericDictionaryCell[] BuildDictionary(TypeBuilder typeBuilder, NativeLayoutInfoLoadContext nativeLayoutInfoLoadContext, NativeParser parser) { uint parserStartOffset = parser.Offset; uint count = parser.GetSequenceCount(); Debug.Assert(count > 0); TypeLoaderLogger.WriteLine("Parsing dictionary layout @ " + parserStartOffset.LowLevelToString() + " (" + count.LowLevelToString() + " entries)"); GenericDictionaryCell[] dictionary = new GenericDictionaryCell[count]; for (uint i = 0; i < count; i++) { TypeLoaderLogger.WriteLine(" -> DictionaryCell[" + i.LowLevelToString() + "] = "); dictionary[i] = ParseAndCreateCell(nativeLayoutInfoLoadContext, ref parser); } for (uint i = 0; i < count; i++) dictionary[i].Prepare(typeBuilder); return dictionary; } internal static GenericDictionaryCell ParseAndCreateCell(NativeLayoutInfoLoadContext nativeLayoutInfoLoadContext, ref NativeParser parser) { GenericDictionaryCell cell; var kind = parser.GetFixupSignatureKind(); switch (kind) { case FixupSignatureKind.TypeHandle: { var type = nativeLayoutInfoLoadContext.GetType(ref parser); TypeLoaderLogger.WriteLine("TypeHandle: " + type.ToString()); cell = new TypeHandleCell() { Type = type }; } break; case FixupSignatureKind.InterfaceCall: { var interfaceType = nativeLayoutInfoLoadContext.GetType(ref parser); var slot = parser.GetUnsigned(); TypeLoaderLogger.WriteLine("InterfaceCall: " + interfaceType.ToString() + ", slot #" + slot.LowLevelToString()); cell = new InterfaceCallCell() { InterfaceType = interfaceType, Slot = (int)slot }; } break; case FixupSignatureKind.GvmDispatchCell: { var method = nativeLayoutInfoLoadContext.GetMethod(ref parser); TypeLoaderLogger.WriteLine("GvmDispatchCell: " + method.OwningType.ToString() + "::" + method.NameAndSignature.GetName()); cell = new GvmDispatchCell() { Method = method }; } break; case FixupSignatureKind.MethodDictionary: { var genericMethod = nativeLayoutInfoLoadContext.GetMethod(ref parser); Debug.Assert(genericMethod.Instantiation.Length > 0); TypeLoaderLogger.WriteLine("MethodDictionary: " + genericMethod.ToString()); cell = new MethodDictionaryCell { GenericMethod = (InstantiatedMethod)genericMethod }; } break; case FixupSignatureKind.StaticData: { var type = nativeLayoutInfoLoadContext.GetType(ref parser); StaticDataKind staticDataKind = (StaticDataKind)parser.GetUnsigned(); TypeLoaderLogger.WriteLine("StaticData (" + (staticDataKind == StaticDataKind.Gc ? "Gc" : "NonGc") + ": " + type.ToString()); cell = new StaticDataCell() { DataKind = staticDataKind, Type = type }; } break; case FixupSignatureKind.UnwrapNullableType: { var type = nativeLayoutInfoLoadContext.GetType(ref parser); TypeLoaderLogger.WriteLine("UnwrapNullableType of: " + type.ToString()); if (type is DefType) cell = new UnwrapNullableTypeCell() { Type = (DefType)type }; else cell = new TypeHandleCell() { Type = type }; } break; case FixupSignatureKind.FieldLdToken: { var type = nativeLayoutInfoLoadContext.GetType(ref parser); int handle = (int)parser.GetUnsigned(); TypeLoaderLogger.WriteLine("LdToken on: " + type.ToString() + "." + handle.LowLevelToString()); cell = new FieldLdTokenCell() { FieldHandle = handle, ContainingType = type }; } break; case FixupSignatureKind.MethodLdToken: { var method = nativeLayoutInfoLoadContext.GetMethod(ref parser); TypeLoaderLogger.WriteLine("LdToken on: " + method.OwningType.ToString() + "::" + method.NameAndSignature.GetName()); cell = new MethodLdTokenCell { Method = method, }; } break; case FixupSignatureKind.AllocateObject: { var type = nativeLayoutInfoLoadContext.GetType(ref parser); TypeLoaderLogger.WriteLine("AllocateObject on: " + type.ToString()); cell = new AllocateObjectCell { Type = type }; } break; case FixupSignatureKind.DefaultConstructor: { var type = nativeLayoutInfoLoadContext.GetType(ref parser); TypeLoaderLogger.WriteLine("DefaultConstructor on: " + type.ToString()); cell = new DefaultConstructorCell { Type = type }; } break; case FixupSignatureKind.Method: { var method = nativeLayoutInfoLoadContext.GetMethod(ref parser); TypeLoaderLogger.WriteLine("Method: " + method.ToString()); cell = new MethodCell { Method = method, }; } break; case FixupSignatureKind.NonGenericStaticConstrainedMethod: case FixupSignatureKind.NonGenericInstanceConstrainedMethod: { var constraintType = nativeLayoutInfoLoadContext.GetType(ref parser); var constrainedMethodType = nativeLayoutInfoLoadContext.GetType(ref parser); var constrainedMethodSlot = parser.GetUnsigned(); string kindString = kind == FixupSignatureKind.NonGenericStaticConstrainedMethod ? "NonGenericStaticConstrainedMethod: " : "NonGenericInstanceConstrainedMethod: "; TypeLoaderLogger.WriteLine(kindString + constraintType.ToString() + " Method " + constrainedMethodType.ToString() + ", slot #" + constrainedMethodSlot.LowLevelToString()); if (kind == FixupSignatureKind.NonGenericStaticConstrainedMethod) { cell = new NonGenericStaticConstrainedMethodCell() { ConstraintType = constraintType, ConstrainedMethodType = constrainedMethodType, ConstrainedMethodSlot = (int)constrainedMethodSlot }; } else { cell = new NonGenericInstanceConstrainedMethodCell() { ConstraintType = constraintType, ConstrainedMethodType = constrainedMethodType, ConstrainedMethodSlot = (int)constrainedMethodSlot }; } } break; case FixupSignatureKind.GenericConstrainedMethod: { TypeDesc constraintType = nativeLayoutInfoLoadContext.GetType(ref parser); MethodDesc constrainedMethod = nativeLayoutInfoLoadContext.GetMethod(ref parser); TypeLoaderLogger.WriteLine("GenericConstrainedMethod: " + constraintType.ToString() + " Method " + constrainedMethod.ToString()); cell = new GenericConstrainedMethodCell() { ConstraintType = (DefType)constraintType, ConstrainedMethod = (InstantiatedMethod)constrainedMethod, }; } break; case FixupSignatureKind.ThreadStaticIndex: { var type = nativeLayoutInfoLoadContext.GetType(ref parser); TypeLoaderLogger.WriteLine("ThreadStaticIndex on: " + type.ToString()); cell = new ThreadStaticIndexCell { Type = type }; } break; case FixupSignatureKind.NotYetSupported: TypeLoaderLogger.WriteLine("Valid dictionary entry, but not yet supported by the TypeLoader!"); throw new TypeBuilder.MissingTemplateException(); default: NativeParser.ThrowBadImageFormatException(); cell = null; break; } return cell; } } }