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), "Necessary type symbol related to CanonicalEETypeNode"); DefType closestDefType = _type.GetClosestDefType(); if (_type.RuntimeInterfaces.Length > 0) { dependencyList.Add(factory.InterfaceDispatchMap(_type), "Canonical interface dispatch map"); } dependencyList.Add(factory.VTable(closestDefType), "VTable"); if (_type.IsCanonicalSubtype(CanonicalFormKind.Universal)) { dependencyList.Add(factory.NativeLayout.TemplateTypeLayout(_type), "Universal generic types always have template layout"); } // Track 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")); AddDependenciesForUniversalGVMSupport(factory, _type, ref dependencyList); } 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), "Necessary type symbol related to CanonicalEETypeNode"); DefType closestDefType = _type.GetClosestDefType(); if (MightHaveInterfaceDispatchMap(factory)) { dependencyList.Add(factory.InterfaceDispatchMap(_type), "Canonical interface dispatch map"); } dependencyList.Add(factory.VTable(closestDefType), "VTable"); if (_type.IsCanonicalSubtype(CanonicalFormKind.Universal)) { dependencyList.Add(factory.NativeLayout.TemplateTypeLayout(_type), "Universal generic types always have template layout"); } // Track generic virtual methods that will get added to the GVM tables if (TypeGVMEntriesNode.TypeNeedsGVMTableEntries(_type)) { dependencyList.Add(new DependencyListEntry(factory.TypeGVMEntries(_type.GetTypeDefinition()), "Type with generic virtual methods")); AddDependenciesForUniversalGVMSupport(factory, _type, ref dependencyList); } // Keep track of the default constructor map dependency for this type if it has a default constructor // We only do this for reflection blocked types because dataflow analysis is responsible for // generating default constructors for Activator.CreateInstance in other cases. MethodDesc defaultCtor = closestDefType.GetDefaultConstructor(); if (defaultCtor != null && factory.MetadataManager.IsReflectionBlocked(defaultCtor)) { dependencyList.Add(new DependencyListEntry( factory.CanonicalEntrypoint(defaultCtor), "DefaultConstructorNode")); } 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 (InterfaceDispatchMapNode.MightHaveInterfaceDispatchMap(_type, factory)) { dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map"); } 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"); ArrayType arrayType = (ArrayType)_type; if (arrayType.IsMdArray && arrayType.Rank == 1) { // Allocating an MDArray of Rank 1 with zero lower bounds results in allocating // an SzArray instead. Make sure the type loader can find the SzArray type. dependencyList.Add(factory.ConstructedTypeSymbol(arrayType.ElementType.MakeArrayType()), "Rank 1 array"); } } dependencyList.Add(factory.VTable(closestDefType), "VTable"); if (closestDefType.HasInstantiation && factory.MetadataManager.SupportsReflection) { TypeDesc canonType = _type.ConvertToCanonForm(CanonicalFormKind.Specific); TypeDesc canonClosestDefType = closestDefType.ConvertToCanonForm(CanonicalFormKind.Specific); // Add a dependency on the template for this type, if the canonical type should be generated into this binary. // If the type is an array type, the check should be on its underlying Array<T> type. This is because a copy of // an array type gets placed into each module but the Array<T> type only exists in the defining module and only // one template is needed for the Array<T> type by the dynamic type loader. if (canonType.IsCanonicalSubtype(CanonicalFormKind.Any) && !factory.NecessaryTypeSymbol(canonClosestDefType).RepresentsIndirectionCell) { dependencyList.Add(factory.NativeLayout.TemplateTypeLayout(canonType), "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")); AddDependenciesForUniversalGVMSupport(factory, _type, ref dependencyList); } 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")); } // Ask the metadata manager if we have any dependencies due to reflectability. factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencyList, factory, _type); factory.InteropStubManager.AddInterestingInteropConstructedTypeDependencies(ref dependencyList, factory, _type); return(dependencyList); }
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) { DefType closestDefType = _type.GetClosestDefType(); DependencyList dependencyList = new DependencyList(); if (_type.RuntimeInterfaces.Length > 0) { 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. if (implementedInterface.HasVariance) { foreach (var interfaceMethod in implementedInterface.GetAllMethods()) { if (interfaceMethod.Signature.IsStatic) { 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()) { // Generic dictionary pointer is part of the vtable and as such it gets only laid out // at the final data emission phase. We need to report it as a non-relocation dependency. dependencyList.Add(factory.TypeGenericDictionary(closestDefType), "Type generic dictionary"); } // Include the optional fields by default. We don't know if optional fields will be needed until // all of the interface usage has been stabilized. If we end up not needing it, the EEType node will not // generate any relocs to it, and the optional fields node will instruct the object writer to skip // emitting it. dependencyList.Add(_optionalFieldsNode, "Optional fields"); // The fact that we generated an EEType means that someone can call RuntimeHelpers.RunClassConstructor. // We need to make sure this is possible - we need the class constructor context. if (factory.TypeSystemContext.HasLazyStaticConstructor(_type)) { dependencyList.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_type), "Class constructor"); } // 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")); } 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 (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 (InterfaceDispatchMapNode.MightHaveInterfaceDispatchMap(_type, factory)) { dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map"); } 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"); ArrayType arrayType = (ArrayType)_type; if (arrayType.IsMdArray && arrayType.Rank == 1) { // Allocating an MDArray of Rank 1 with zero lower bounds results in allocating // an SzArray instead. Make sure the type loader can find the SzArray type. dependencyList.Add(factory.ConstructedTypeSymbol(arrayType.ElementType.MakeArrayType()), "Rank 1 array"); } } dependencyList.Add(factory.VTable(closestDefType), "VTable"); if (factory.TypeSystemContext.SupportsUniversalCanon) { foreach (var instantiationType in _type.Instantiation) { if (instantiationType.IsValueType) { // All valuetype generic parameters of a constructed type may be effectively constructed. This is generally not that // critical, but in the presence of universal generics the compiler may generate a Box followed by calls to ToString, // GetHashcode or Equals in ways that cannot otherwise be detected by dependency analysis. Thus force all struct type // generic parameters to be considered constructed when walking dependencies of a constructed generic dependencyList.Add(factory.ConstructedTypeSymbol(instantiationType.ConvertToCanonForm(CanonicalFormKind.Specific)), "Struct generic parameters in constructed types may be assumed to be used as constructed in constructed generic types"); } } } // 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")); AddDependenciesForUniversalGVMSupport(factory, _type, ref dependencyList); } if (factory.PreinitializationManager.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")); } // Ask the metadata manager if we have any dependencies due to reflectability. factory.MetadataManager.GetDependenciesDueToReflectability(ref dependencyList, factory, _type); factory.InteropStubManager.AddInterestingInteropConstructedTypeDependencies(ref dependencyList, factory, _type); // Keep track of the default constructor map dependency for this type if it has a default constructor MethodDesc defaultCtor = closestDefType.GetDefaultConstructor(); if (defaultCtor != null) { dependencyList.Add(new DependencyListEntry( factory.MethodEntrypoint(defaultCtor.GetCanonMethodTarget(CanonicalFormKind.Specific), closestDefType.IsValueType), "DefaultConstructorNode")); } 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); }
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) { DependencyList dependencyList = base.ComputeNonRelocationBasedDependencies(factory); 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. if (implementedInterface.HasVariance) { foreach (var interfaceMethod in implementedInterface.GetAllMethods()) { if (interfaceMethod.Signature.IsStatic) { 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()) { // Generic dictionary pointer is part of the vtable and as such it gets only laid out // at the final data emission phase. We need to report it as a non-relocation dependency. dependencyList.Add(factory.TypeGenericDictionary(closestDefType), "Type generic dictionary"); } // 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")); } return(dependencyList); }