// 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 Internal.Text; using System.Diagnostics; using System.Reflection; using System.Reflection.Metadata; using Internal.ReadyToRunConstants; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; namespace ILCompiler.DependencyAnalysis.ReadyToRun { public class TypeGenericInfoMapNode : ModuleSpecificHeaderTableNode { private MetadataReader _metadata; public TypeGenericInfoMapNode(EcmaModule module) : base (module) { _metadata = module.MetadataReader; } public static bool IsSupported(MetadataReader metadata) { // Only support this map with R2R images of some size return metadata.TypeDefinitions.Count > 16; } public override int ClassCode => 1329419084; protected override string ModuleSpecificName => "__TypeGenericInfoMapNode__"; public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this }); ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly); builder.AddSymbol(this); builder.EmitUInt((uint)_metadata.TypeDefinitions.Count); int usedBits = 0; byte curByte = 0; foreach (var typeDefinitionHandle in _metadata.TypeDefinitions) { var typeDefinition = _metadata.GetTypeDefinition(typeDefinitionHandle); bool isGeneric = typeDefinition.GetGenericParameters().Count > 0; ReadyToRunTypeGenericInfo genericInfo = default(ReadyToRunTypeGenericInfo); bool hasVariance = false; bool hasConstraints = false; foreach (var genericParameterHandle in typeDefinition.GetGenericParameters()) { var genericParameter = _metadata.GetGenericParameter(genericParameterHandle); if ((genericParameter.Attributes & GenericParameterAttributes.VarianceMask) != GenericParameterAttributes.None) hasVariance = true; if ((genericParameter.Attributes & (GenericParameterAttributes.SpecialConstraintMask | (GenericParameterAttributes)GenericConstraints.AllowByRefLike)) != default(GenericParameterAttributes) || (genericParameter.GetConstraints().Count > 0)) { hasConstraints = true; } } ReadyToRunGenericInfoGenericCount count; switch (typeDefinition.GetGenericParameters().Count) { case 0: count = ReadyToRunGenericInfoGenericCount.Zero; break; case 1: count = ReadyToRunGenericInfoGenericCount.One; break; case 2: count = ReadyToRunGenericInfoGenericCount.Two; break; default: count = ReadyToRunGenericInfoGenericCount.MoreThanTwo; break; } genericInfo = (ReadyToRunTypeGenericInfo)count | (hasVariance ? ReadyToRunTypeGenericInfo.HasVariance : default(ReadyToRunTypeGenericInfo)) | (hasConstraints ? ReadyToRunTypeGenericInfo.HasConstraints : default(ReadyToRunTypeGenericInfo)); curByte |= (byte)genericInfo; usedBits += 4; if (usedBits == 8) { builder.EmitByte(curByte); usedBits = 0; curByte = 0; } else { curByte <<= 4; } } if (usedBits != 0) builder.EmitByte(curByte); return builder.ToObjectData(); } } } |