| File: Compiler\DependencyAnalysis\ReadyToRun\TypeFixupSignature.cs | Web Access |
| Project: src\runtime\src\coreclr\tools\aot\ILCompiler.ReadyToRun\ILCompiler.ReadyToRun.csproj (ILCompiler.ReadyToRun) |
// 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 Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; using Internal.TypeSystem.Interop; using Internal.ReadyToRunConstants; using Internal.CorConstants; using Internal.JitInterface; namespace ILCompiler.DependencyAnalysis.ReadyToRun { public class TypeFixupSignature : Signature { private readonly ReadyToRunFixupKind _fixupKind; private readonly TypeDesc _typeDesc; public TypeFixupSignature(ReadyToRunFixupKind fixupKind, TypeDesc typeDesc) { _fixupKind = fixupKind; _typeDesc = typeDesc; // Ensure types in signature are loadable and resolvable, otherwise we'll fail later while emitting the signature ((CompilerTypeSystemContext)typeDesc.Context).EnsureLoadableType(typeDesc); } public override int ClassCode => 255607008; public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { ObjectDataSignatureBuilder dataBuilder = new ObjectDataSignatureBuilder(factory, relocsOnly); if (!relocsOnly) { ReadyToRunFixupKind fixupKind = _fixupKind; dataBuilder.AddSymbol(this); if ((fixupKind == ReadyToRunFixupKind.Verify_TypeLayout) && ((MetadataType)_typeDesc).IsVectorTOrHasVectorTFields) { fixupKind = ReadyToRunFixupKind.Check_TypeLayout; } IEcmaModule targetModule = factory.SignatureContext.GetTargetModule(_typeDesc); SignatureContext innerContext = dataBuilder.EmitFixup(factory, fixupKind, targetModule, factory.SignatureContext); if ((fixupKind == ReadyToRunFixupKind.Check_TypeLayout) || (fixupKind == ReadyToRunFixupKind.Verify_TypeLayout)) { dataBuilder.EmitTypeSignature(_typeDesc, innerContext); Debug.Assert(_typeDesc.IsValueType); EncodeTypeLayout(dataBuilder, _typeDesc); } else if (fixupKind == ReadyToRunFixupKind.ContinuationLayout) { var act = _typeDesc as AsyncContinuationType; // Emit EcmaType Continuation type dataBuilder.EmitTypeSignature(act.BaseType, innerContext); EncodeContinuationTypeLayout(dataBuilder, act); } else { dataBuilder.EmitTypeSignature(_typeDesc, innerContext); } } return dataBuilder.ToObjectData(); } private static void EncodeTypeLayout(ObjectDataSignatureBuilder dataBuilder, TypeDesc type) { Debug.Assert(type.IsValueType); MetadataType defType = (MetadataType)type; int pointerSize = type.Context.Target.PointerSize; int size = defType.InstanceFieldSize.AsInt; int alignment = Internal.JitInterface.CorInfoImpl.GetClassAlignmentRequirementStatic(defType); ReadyToRunTypeLayoutFlags flags = ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment | ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout; if (alignment == pointerSize) { flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment_Native; } if (!defType.ContainsGCPointers) { flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout_Empty; } if (defType.IsHomogeneousAggregate) { flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_HFA; } dataBuilder.EmitUInt((uint)flags); dataBuilder.EmitUInt((uint)size); if (defType.IsHomogeneousAggregate) { ReadyToRunHFAElemType hfaElementType = (defType.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch { ValueTypeShapeCharacteristics.Float32Aggregate => ReadyToRunHFAElemType.Float32, ValueTypeShapeCharacteristics.Float64Aggregate => ReadyToRunHFAElemType.Float64, ValueTypeShapeCharacteristics.Vector64Aggregate => ReadyToRunHFAElemType.Vector64, // See MethodTable::GetHFAType ValueTypeShapeCharacteristics.Vector128Aggregate => ReadyToRunHFAElemType.Vector128, _ => throw new NotSupportedException() }; dataBuilder.EmitUInt((uint)hfaElementType); } if (alignment != pointerSize) { dataBuilder.EmitUInt((uint)alignment); } if (defType.ContainsGCPointers) { // Encode the GC pointer map GCPointerMap gcMap = GCPointerMap.FromInstanceLayout(defType); byte[] encodedGCRefMap = new byte[((size + (pointerSize - 1)) / pointerSize + 7) / 8]; int bitIndex = 0; foreach (bool bit in gcMap) { if (bit) { encodedGCRefMap[bitIndex / 8] |= (byte)(1 << (bitIndex & 7)); } ++bitIndex; } dataBuilder.EmitBytes(encodedGCRefMap); } } private static void EncodeContinuationTypeLayout(ObjectDataSignatureBuilder dataBuilder, AsyncContinuationType type) { int pointerSize = type.Context.Target.PointerSize; int size = type.PointerMap.Size * pointerSize; int alignment = pointerSize; ReadyToRunTypeLayoutFlags flags = ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment | ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout; Debug.Assert(alignment == pointerSize); flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment_Native; bool gcLayoutEmpty = true; foreach (bool hasPointer in type.PointerMap) { if (hasPointer) { gcLayoutEmpty = false; break; } } if (gcLayoutEmpty) { flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout_Empty; } dataBuilder.EmitUInt((uint)flags); dataBuilder.EmitUInt((uint)size); if (!gcLayoutEmpty) { // Encode the GC pointer map GCPointerMap gcMap = type.PointerMap; byte[] encodedGCRefMap = new byte[(size / pointerSize + 7) / 8]; int bitIndex = 0; foreach (bool bit in gcMap) { if (bit) { encodedGCRefMap[bitIndex / 8] |= (byte)(1 << (bitIndex & 7)); } ++bitIndex; } dataBuilder.EmitBytes(encodedGCRefMap); } } public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); sb.Append($@"TypeFixupSignature({_fixupKind.ToString()}): "); sb.Append(nameMangler.GetMangledTypeName(_typeDesc)); } public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { TypeFixupSignature otherNode = (TypeFixupSignature)other; int result = ((int)_fixupKind).CompareTo((int)otherNode._fixupKind); if (result != 0) return result; return comparer.Compare(_typeDesc, otherNode._typeDesc); } protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) { DependencyList dependencies = new DependencyList(); if (_typeDesc.HasInstantiation && !_typeDesc.IsGenericDefinition && (factory.CompilationCurrentPhase == 0) && factory.CompilationModuleGroup.VersionsWithType(_typeDesc)) { dependencies.Add(factory.AllMethodsOnType(_typeDesc), "Methods on generic type instantiation"); } // We record the usage of this type, so that virtual method dependency analysis can resolve implementations. // GVMDependenciesNode uses this for generic virtual methods (dynamic dependencies). // InheritedVirtualMethodsNode uses conditional static dependencies for non-GVM virtual methods. if (!_typeDesc.IsGenericDefinition && !_typeDesc.IsInterface && _typeDesc.IsDefType && (factory.CompilationCurrentPhase == 0) && factory.CompilationModuleGroup.VersionsWithType(_typeDesc)) { dependencies.Add(factory.InheritedVirtualMethods(_typeDesc), "Inherited virtual/interface methods on type"); } if (_fixupKind == ReadyToRunFixupKind.TypeHandle) { AddDependenciesForAsyncStateMachineBox(ref dependencies, factory, _typeDesc); } return dependencies; } public static void AddDependenciesForAsyncStateMachineBox(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) { ReadyToRunCompilerContext context = (ReadyToRunCompilerContext)type.Context; // If adding a typehandle to the AsyncStateMachineBox, pre-compile the most commonly used methods. // As long as we haven't already reached compilation phase 7, which is an arbitrary number of phases of compilation chosen so that // simple examples of async will get compiled if (factory.OptimizationFlags.OptimizeAsyncMethods && type.GetTypeDefinition() == context.AsyncStateMachineBoxType && !type.IsGenericDefinition && factory.CompilationCurrentPhase <= 7) { if (dependencies == null) dependencies = new DependencyList(); // This is the async state machine box, compile the cctor, and the MoveNext method. foreach (MethodDesc method in type.ConvertToCanonForm(CanonicalFormKind.Specific).GetAllMethods()) { if (!method.IsGenericMethodDefinition && factory.CompilationModuleGroup.ContainsMethodBody(method, false)) { switch (method.GetName()) { case "MoveNext": case ".cctor": try { factory.DetectGenericCycles(type, method); dependencies.Add(factory.CompiledMethodNode(method), $"AsyncStateMachineBox Method on type {type.ToString()}"); } catch (TypeSystemException) { } break; } } } } } } }