public static void AddDependenciesDueToMethodCodePresence(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) { factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, method); if (method.HasInstantiation) { ExactMethodInstantiationsNode.GetExactMethodInstantiationDependenciesForMethod(ref dependencies, factory, method); if (method.IsVirtual) { // Generic virtual methods dependency tracking dependencies = dependencies ?? new DependencyList(); dependencies.Add(new DependencyListEntry(factory.GVMDependencies(method), "GVM Dependencies Support")); } GenericMethodsTemplateMap.GetTemplateMethodDependencies(ref dependencies, factory, method); } else { TypeDesc owningTemplateType = method.OwningType; // Unboxing and Instantiating stubs use a different type as their template if (factory.TypeSystemContext.IsSpecialUnboxingThunk(method)) { owningTemplateType = factory.TypeSystemContext.GetTargetOfSpecialUnboxingThunk(method).OwningType; } GenericTypesTemplateMap.GetTemplateTypeDependencies(ref dependencies, factory, owningTemplateType); } factory.InteropStubManager.AddDependeciesDueToPInvoke(ref dependencies, factory, method); }
public static void AddDependenciesDueToMethodCodePresence(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) { factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, method); if (method.HasInstantiation) { ExactMethodInstantiationsNode.GetExactMethodInstantiationDependenciesForMethod(ref dependencies, factory, method); if (method.IsVirtual) { // Generic virtual methods dependency tracking dependencies = dependencies ?? new DependencyList(); dependencies.Add(new DependencyListEntry(factory.GVMDependencies(method), "GVM Dependencies Support")); } GenericMethodsTemplateMap.GetTemplateMethodDependencies(ref dependencies, factory, method); } else { TypeDesc owningTemplateType = method.OwningType; // Unboxing and Instantiating stubs use a different type as their template if (factory.TypeSystemContext.IsSpecialUnboxingThunk(method)) { owningTemplateType = factory.TypeSystemContext.GetTargetOfSpecialUnboxingThunk(method).OwningType; } GenericTypesTemplateMap.GetTemplateTypeDependencies(ref dependencies, factory, owningTemplateType); } // On Project N, the compiler doesn't generate the interop code on the fly if (method.Context.Target.Abi != TargetAbi.ProjectN) { if (method.IsPInvoke) { if (dependencies == null) { dependencies = new DependencyList(); } MethodSignature methodSig = method.Signature; AddPInvokeParameterDependencies(ref dependencies, factory, methodSig.ReturnType); for (int i = 0; i < methodSig.Length; i++) { AddPInvokeParameterDependencies(ref dependencies, factory, methodSig[i]); } } } }
public override IEnumerable <CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory) { List <CombinedDependencyListEntry> conditionalDependencies = new List <CombinedDependencyListEntry>(); NativeLayoutSavedVertexNode templateLayout; if (_dictionaryOwner is MethodDesc) { templateLayout = factory.NativeLayout.TemplateMethodLayout((MethodDesc)_dictionaryOwner); conditionalDependencies.Add(new CombinedDependencyListEntry(_lookupSignature.TemplateDictionaryNode(factory), templateLayout, "Type loader template")); } else { DefType actualTemplateType = GenericTypesTemplateMap.GetActualTemplateTypeForType(factory, (TypeDesc)_dictionaryOwner); templateLayout = factory.NativeLayout.TemplateTypeLayout(actualTemplateType); conditionalDependencies.Add(new CombinedDependencyListEntry(_lookupSignature.TemplateDictionaryNode(factory), templateLayout, "Type loader template")); } if (_id == ReadyToRunHelperId.GetGCStaticBase || _id == ReadyToRunHelperId.GetThreadStaticBase) { // If the type has a lazy static constructor, we also need the non-GC static base to be available as // a template dictionary node. TypeDesc type = (TypeDesc)_target; Debug.Assert(templateLayout != null); if (factory.TypeSystemContext.HasLazyStaticConstructor(type)) { GenericLookupResult nonGcRegionLookup = factory.GenericLookup.TypeNonGCStaticBase(type); conditionalDependencies.Add(new CombinedDependencyListEntry(nonGcRegionLookup.TemplateDictionaryNode(factory), templateLayout, "Type loader template")); } } return(conditionalDependencies); }
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) { DependencyList dependencies = new DependencyList(); foreach (DependencyNodeCore <NodeFactory> dependency in _lookupSignature.NonRelocDependenciesFromUsage(factory)) { dependencies.Add(new DependencyListEntry(dependency, "GenericLookupResultDependency")); } // Root the template for the type while we're hitting its dictionary cells. In the future, we may // want to control this via type reflectability instead. if (_dictionaryOwner is MethodDesc) { dependencies.Add(factory.NativeLayout.TemplateMethodLayout((MethodDesc)_dictionaryOwner), "Type loader template"); } else { DefType actualTemplateType = GenericTypesTemplateMap.GetActualTemplateTypeForType(factory, (TypeDesc)_dictionaryOwner); dependencies.Add(factory.NativeLayout.TemplateTypeLayout(actualTemplateType), "Type loader template"); } return(dependencies); }
static void AddSignatureDependency(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) { if (type.IsByRef) { type = ((ParameterizedType)type).ParameterType; } // Pointer runtime type handles can be created at runtime if necessary while (type.IsPointer) { type = ((ParameterizedType)type).ParameterType; } // Skip tracking dependencies for primitive types. Assume that they are always present. if (type.IsPrimitive || type.IsVoid) { return; } // Function pointers are not supported yet. // https://github.com/dotnet/runtime/issues/71883 if (type.IsFunctionPointer) { return; } TypeDesc canonType = type.ConvertToCanonForm(CanonicalFormKind.Specific); if (canonType.IsCanonicalSubtype(CanonicalFormKind.Any)) { GenericTypesTemplateMap.GetTemplateTypeDependencies(ref dependencies, factory, type.ConvertToCanonForm(CanonicalFormKind.Specific)); } else { dependencies.Add(factory.MaximallyConstructableType(canonType), "Reflection invoke"); } }
public NativeLayoutTemplateTypeLayoutVertexNode TemplateTypeLayout(TypeDesc type) { return(_templateTypeLayouts.GetOrAdd(GenericTypesTemplateMap.ConvertArrayOfTToRegularArray(_factory, type))); }
public static void AddDependenciesDueToMethodCodePresence(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) { factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencies, factory, method); if (method.HasInstantiation) { ExactMethodInstantiationsNode.GetExactMethodInstantiationDependenciesForMethod(ref dependencies, factory, method); GenericMethodsTemplateMap.GetTemplateMethodDependencies(ref dependencies, factory, method); } else { TypeDesc owningTemplateType = method.OwningType; // Unboxing and Instantiating stubs use a different type as their template if (factory.TypeSystemContext.IsSpecialUnboxingThunk(method)) { owningTemplateType = factory.TypeSystemContext.GetTargetOfSpecialUnboxingThunk(method).OwningType; } GenericTypesTemplateMap.GetTemplateTypeDependencies(ref dependencies, factory, owningTemplateType); } factory.InteropStubManager.AddDependeciesDueToPInvoke(ref dependencies, factory, method); if (method.IsIntrinsic && factory.MetadataManager.SupportsReflection) { if (method.OwningType is MetadataType owningType) { string name = method.Name; switch (name) { // The general purpose code in Comparer/EqualityComparer Create method depends on the template // type loader being able to load the necessary types at runtime. case "Create": if (method.IsSharedByGenericInstantiations && owningType.Module == factory.TypeSystemContext.SystemModule && owningType.Namespace == "System.Collections.Generic") { TypeDesc[] templateDependencies = null; if (owningType.Name == "Comparer`1") { templateDependencies = Internal.IL.Stubs.ComparerIntrinsics.GetPotentialComparersForType( owningType.Instantiation[0]); } else if (owningType.Name == "EqualityComparer`1") { templateDependencies = Internal.IL.Stubs.ComparerIntrinsics.GetPotentialEqualityComparersForType( owningType.Instantiation[0]); } if (templateDependencies != null) { dependencies = dependencies ?? new DependencyList(); foreach (TypeDesc templateType in templateDependencies) { dependencies.Add(factory.NativeLayout.TemplateTypeLayout(templateType), "Generic comparer"); } } } break; } } } }
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) { DependencyList dependencyList = base.ComputeNonRelocationBasedDependencies(factory); // Ensure that we track the necessary type symbol if we are working with a constructed type symbol. // The emitter will ensure we don't emit both, but this allows us assert that we only generate // relocs to nodes we emit. dependencyList.Add(factory.NecessaryTypeSymbol(_type), "NecessaryType for constructed type"); DefType closestDefType = _type.GetClosestDefType(); if (TrackInterfaceDispatchMapDepenendency && _type.RuntimeInterfaces.Length > 0) { dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map"); } if (_type.RuntimeInterfaces.Length > 0 && !factory.CompilationModuleGroup.ShouldProduceFullVTable(_type)) { foreach (var implementedInterface in _type.RuntimeInterfaces) { // If the type implements ICastable, the methods are implicitly necessary if (implementedInterface == factory.ICastableInterface) { MethodDesc isInstDecl = implementedInterface.GetKnownMethod("IsInstanceOfInterface", null); MethodDesc getImplTypeDecl = implementedInterface.GetKnownMethod("GetImplType", null); MethodDesc isInstMethodImpl = _type.ResolveInterfaceMethodTarget(isInstDecl); MethodDesc getImplTypeMethodImpl = _type.ResolveInterfaceMethodTarget(getImplTypeDecl); if (isInstMethodImpl != null) { dependencyList.Add(factory.VirtualMethodUse(isInstMethodImpl), "ICastable IsInst"); } if (getImplTypeMethodImpl != null) { dependencyList.Add(factory.VirtualMethodUse(getImplTypeMethodImpl), "ICastable GetImplType"); } } // If any of the implemented interfaces have variance, calls against compatible interface methods // could result in interface methods of this type being used (e.g. IEnumberable<object>.GetEnumerator() // can dispatch to an implementation of IEnumerable<string>.GetEnumerator()). // For now, we will not try to optimize this and we will pretend all interface methods are necessary. bool allInterfaceMethodsAreImplicitlyUsed = false; if (implementedInterface.HasVariance) { TypeDesc interfaceDefinition = implementedInterface.GetTypeDefinition(); for (int i = 0; i < interfaceDefinition.Instantiation.Length; i++) { if (((GenericParameterDesc)interfaceDefinition.Instantiation[i]).Variance != 0 && !implementedInterface.Instantiation[i].IsValueType) { allInterfaceMethodsAreImplicitlyUsed = true; break; } } } if (!allInterfaceMethodsAreImplicitlyUsed && (_type.IsArray || _type.GetTypeDefinition() == factory.ArrayOfTEnumeratorType) && implementedInterface.HasInstantiation) { // NOTE: we need to also do this for generic interfaces on arrays because they have a weird casting rule // that doesn't require the implemented interface to be variant to consider it castable. // For value types, we only need this when the array is castable by size (int[] and ICollection<uint>), // or it's a reference type (Derived[] and ICollection<Base>). TypeDesc elementType = _type.IsArray ? ((ArrayType)_type).ElementType : _type.Instantiation[0]; allInterfaceMethodsAreImplicitlyUsed = CastingHelper.IsArrayElementTypeCastableBySize(elementType) || (elementType.IsDefType && !elementType.IsValueType); } if (allInterfaceMethodsAreImplicitlyUsed) { foreach (var interfaceMethod in implementedInterface.GetAllMethods()) { if (interfaceMethod.Signature.IsStatic) { continue; } // Generic virtual methods are tracked by an orthogonal mechanism. if (interfaceMethod.HasInstantiation) { continue; } MethodDesc implMethod = closestDefType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod); if (implMethod != null) { dependencyList.Add(factory.VirtualMethodUse(interfaceMethod), "Variant interface method"); dependencyList.Add(factory.VirtualMethodUse(implMethod), "Variant interface method"); } } } } } if (_type.IsArray) { // Array EEType depends on System.Array's virtuals. Array EETypes don't point to // their base type (i.e. there's no reloc based dependency making this "just work"). dependencyList.Add(factory.ConstructedTypeSymbol(_type.BaseType), "Array base type"); } dependencyList.Add(factory.VTable(_type), "VTable"); if (closestDefType.HasGenericDictionarySlot()) { // Add a dependency on the template for this type, if the canonical type should be generated into this binary. DefType templateType = GenericTypesTemplateMap.GetActualTemplateTypeForType(factory, _type.ConvertToCanonForm(CanonicalFormKind.Specific)); if (templateType.IsCanonicalSubtype(CanonicalFormKind.Any) && !factory.NecessaryTypeSymbol(templateType).RepresentsIndirectionCell) { dependencyList.Add(factory.NativeLayout.TemplateTypeLayout(templateType), "Template Type Layout"); } } // Generated type contains generic virtual methods that will get added to the GVM tables if (TypeGVMEntriesNode.TypeNeedsGVMTableEntries(_type)) { dependencyList.Add(new DependencyListEntry(factory.TypeGVMEntries(_type), "Type with generic virtual methods")); } if (factory.TypeSystemContext.HasLazyStaticConstructor(_type)) { // The fact that we generated an EEType means that someone can call RuntimeHelpers.RunClassConstructor. // We need to make sure this is possible. dependencyList.Add(new DependencyListEntry(factory.TypeNonGCStaticsSymbol((MetadataType)_type), "Class constructor")); } return(dependencyList); }
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) { DependencyList dependencyList = base.ComputeNonRelocationBasedDependencies(factory); // Ensure that we track the necessary type symbol if we are working with a constructed type symbol. // The emitter will ensure we don't emit both, but this allows us assert that we only generate // relocs to nodes we emit. dependencyList.Add(factory.NecessaryTypeSymbol(_type), "NecessaryType for constructed type"); DefType closestDefType = _type.GetClosestDefType(); if (_type.RuntimeInterfaces.Length > 0) { if (TrackInterfaceDispatchMapDepenendency) { dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map"); } foreach (var implementedInterface in _type.RuntimeInterfaces) { // If the type implements ICastable, the methods are implicitly necessary if (implementedInterface == factory.ICastableInterface) { MethodDesc isInstDecl = implementedInterface.GetKnownMethod("IsInstanceOfInterface", null); MethodDesc getImplTypeDecl = implementedInterface.GetKnownMethod("GetImplType", null); MethodDesc isInstMethodImpl = _type.ResolveInterfaceMethodTarget(isInstDecl); MethodDesc getImplTypeMethodImpl = _type.ResolveInterfaceMethodTarget(getImplTypeDecl); if (isInstMethodImpl != null) { dependencyList.Add(factory.VirtualMethodUse(isInstMethodImpl), "ICastable IsInst"); } if (getImplTypeMethodImpl != null) { dependencyList.Add(factory.VirtualMethodUse(getImplTypeMethodImpl), "ICastable GetImplType"); } } // If any of the implemented interfaces have variance, calls against compatible interface methods // could result in interface methods of this type being used (e.g. IEnumberable<object>.GetEnumerator() // can dispatch to an implementation of IEnumerable<string>.GetEnumerator()). // For now, we will not try to optimize this and we will pretend all interface methods are necessary. // NOTE: we need to also do this for generic interfaces on arrays because they have a weird casting rule // that doesn't require the implemented interface to be variant to consider it castable. if (implementedInterface.HasVariance || (_type.IsArray && implementedInterface.HasInstantiation)) { foreach (var interfaceMethod in implementedInterface.GetAllMethods()) { if (interfaceMethod.Signature.IsStatic) { continue; } // Generic virtual methods are tracked by an orthogonal mechanism. if (interfaceMethod.HasInstantiation) { continue; } MethodDesc implMethod = closestDefType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod); if (implMethod != null) { dependencyList.Add(factory.VirtualMethodUse(interfaceMethod), "Variant interface method"); dependencyList.Add(factory.VirtualMethodUse(implMethod), "Variant interface method"); } } } } } if (_type.IsArray) { // Array EEType depends on System.Array's virtuals. Array EETypes don't point to // their base type (i.e. there's no reloc based dependency making this "just work"). dependencyList.Add(factory.ConstructedTypeSymbol(_type.BaseType), "Array base type"); } dependencyList.Add(factory.VTable(_type), "VTable"); if (closestDefType.HasGenericDictionarySlot()) { // Add a dependency on the template for this type, if the canonical type should be generated into this binary. DefType templateType = GenericTypesTemplateMap.GetActualTemplateTypeForType(factory, _type.ConvertToCanonForm(CanonicalFormKind.Specific)); if (templateType.IsCanonicalSubtype(CanonicalFormKind.Any) && !factory.NecessaryTypeSymbol(templateType).RepresentsIndirectionCell) { dependencyList.Add(factory.NativeLayout.TemplateTypeLayout(templateType), "Template Type Layout"); } } // Generated type contains generic virtual methods that will get added to the GVM tables if (TypeGVMEntriesNode.TypeNeedsGVMTableEntries(_type)) { dependencyList.Add(new DependencyListEntry(factory.TypeGVMEntries(_type), "Type with generic virtual methods")); } if (factory.TypeSystemContext.HasLazyStaticConstructor(_type)) { // The fact that we generated an EEType means that someone can call RuntimeHelpers.RunClassConstructor. // We need to make sure this is possible. dependencyList.Add(new DependencyListEntry(factory.TypeNonGCStaticsSymbol((MetadataType)_type), "Class constructor")); } // Dependencies of the StaticsInfoHashTable and the ReflectionFieldAccessMap if (_type is MetadataType) { MetadataType metadataType = (MetadataType)_type; // NOTE: The StaticsInfoHashtable entries need to reference the gc and non-gc static nodes through an indirection cell. // The StaticsInfoHashtable entries only exist for static fields on generic types. if (metadataType.GCStaticFieldSize.AsInt > 0) { ISymbolNode gcStatics = factory.TypeGCStaticsSymbol(metadataType); dependencyList.Add(_type.HasInstantiation ? factory.Indirection(gcStatics) : gcStatics, "GC statics indirection for StaticsInfoHashtable"); } if (metadataType.NonGCStaticFieldSize.AsInt > 0) { ISymbolNode nonGCStatic = factory.TypeNonGCStaticsSymbol(metadataType); if (_type.HasInstantiation) { // The entry in the StaticsInfoHashtable points at the begining of the static fields data, so we need to add // the cctor context offset to the indirection cell. int cctorOffset = 0; if (factory.TypeSystemContext.HasLazyStaticConstructor(metadataType)) { cctorOffset += NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.TypeSystemContext.Target, metadataType); } nonGCStatic = factory.Indirection(nonGCStatic, cctorOffset); } dependencyList.Add(nonGCStatic, "Non-GC statics indirection for StaticsInfoHashtable"); } // TODO: TLS dependencies } return(dependencyList); }
public static void AddDependenciesDueToMethodCodePresence(ref DependencyList dependencies, NodeFactory factory, MethodDesc method) { // Reflection invoke stub handling is here because in the current reflection model we reflection-enable // all methods that are compiled. Ideally the list of reflection enabled methods should be known before // we even start the compilation process (with the invocation stubs being compilation roots like any other). // The existing model has it's problems: e.g. the invocability of the method depends on inliner decisions. if (factory.MetadataManager.IsReflectionInvokable(method)) { if (dependencies == null) { dependencies = new DependencyList(); } if (factory.MetadataManager.HasReflectionInvokeStubForInvokableMethod(method) && !method.IsCanonicalMethod(CanonicalFormKind.Any) /* Shared generics handled in the shadow concrete method node */) { MethodDesc invokeStub = factory.MetadataManager.GetReflectionInvokeStub(method); MethodDesc canonInvokeStub = invokeStub.GetCanonMethodTarget(CanonicalFormKind.Specific); if (invokeStub != canonInvokeStub) { dependencies.Add(new DependencyListEntry(factory.FatFunctionPointer(invokeStub), "Reflection invoke")); } else { dependencies.Add(new DependencyListEntry(factory.MethodEntrypoint(invokeStub), "Reflection invoke")); } } bool skipUnboxingStubDependency = false; if (factory.Target.Abi == TargetAbi.ProjectN) { // ProjectN compilation currently computes the presence of these stubs independent from dependency analysis here // TODO: fix that issue and remove this odd treatment of unboxing stubs if (!method.HasInstantiation && method.OwningType.IsValueType && method.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any) && !method.Signature.IsStatic) { skipUnboxingStubDependency = true; } } if (method.OwningType.IsValueType && !method.Signature.IsStatic && !skipUnboxingStubDependency) { dependencies.Add(new DependencyListEntry(factory.MethodEntrypoint(method, unboxingStub: true), "Reflection unboxing stub")); } dependencies.AddRange(ReflectionVirtualInvokeMapNode.GetVirtualInvokeMapDependencies(factory, method)); } if (method.HasInstantiation) { var exactMethodInstantiationDependencies = ExactMethodInstantiationsNode.GetExactMethodInstantiationDependenciesForMethod(factory, method); if (exactMethodInstantiationDependencies != null) { dependencies = dependencies ?? new DependencyList(); dependencies.AddRange(exactMethodInstantiationDependencies); } if (method.IsVirtual) { // Generic virtual methods dependency tracking dependencies = dependencies ?? new DependencyList(); dependencies.Add(new DependencyListEntry(factory.GVMDependencies(method), "GVM Dependencies Support")); } var templateMethodDependencies = GenericMethodsTemplateMap.GetTemplateMethodDependencies(factory, method); if (templateMethodDependencies != null) { dependencies = dependencies ?? new DependencyList(); dependencies.AddRange(templateMethodDependencies); } } else { TypeDesc owningTemplateType = method.OwningType; // Unboxing and Instantiating stubs use a different type as their template if (factory.TypeSystemContext.IsSpecialUnboxingThunk(method)) { owningTemplateType = factory.TypeSystemContext.GetTargetOfSpecialUnboxingThunk(method).OwningType; } var templateTypeDepedencies = GenericTypesTemplateMap.GetTemplateTypeDependencies(factory, owningTemplateType); if (templateTypeDepedencies != null) { dependencies = dependencies ?? new DependencyList(); dependencies.AddRange(templateTypeDepedencies); } } }