public static void RootType(IRootingServiceProvider rootProvider, TypeDesc type, string reason) { rootProvider.AddCompilationRoot(type, reason); InstantiatedType fallbackNonCanonicalOwningType = null; // Instantiate generic types over something that will be useful at runtime if (type.IsGenericDefinition) { Instantiation canonInst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: true); if (canonInst.IsNull) { return; } Instantiation concreteInst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: false); if (!concreteInst.IsNull) { fallbackNonCanonicalOwningType = ((MetadataType)type).MakeInstantiatedType(concreteInst); } type = ((MetadataType)type).MakeInstantiatedType(canonInst); rootProvider.AddCompilationRoot(type, reason); } // Also root base types. This is so that we make methods on the base types callable. // This helps in cases like "class Foo : Bar<int> { }" where we discover new // generic instantiations. TypeDesc baseType = type.BaseType; if (baseType != null) { RootType(rootProvider, baseType.NormalizeInstantiation(), reason); } if (type.IsDefType) { foreach (var method in type.GetMethods()) { if (method.HasInstantiation) { // Make a non-canonical instantiation. // We currently have a file format limitation that requires generic methods to be concrete. // A rooted canonical method body is not visible to the reflection mapping tables. Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(method.Instantiation, allowCanon: false); if (inst.IsNull) { // Can't root anything useful } else if (!method.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) { // Owning type is not canonical, can use the instantiation directly. TryRootMethod(rootProvider, method.MakeInstantiatedMethod(inst), reason); } else if (fallbackNonCanonicalOwningType != null) { // We have a fallback non-canonical type we can root a body on MethodDesc alternateMethod = method.Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), fallbackNonCanonicalOwningType); TryRootMethod(rootProvider, alternateMethod.MakeInstantiatedMethod(inst), reason); } } else { TryRootMethod(rootProvider, method, reason); } } } }
public static bool TryGetDependenciesForReflectedMethod(ref DependencyList dependencies, NodeFactory factory, MethodDesc method, string reason) { MethodDesc typicalMethod = method.GetTypicalMethodDefinition(); if (factory.MetadataManager.IsReflectionBlocked(typicalMethod)) { return(false); } // If this is a generic method, make sure we at minimum have the metadata // for it. This hedges against the risk that we fail to figure out a code body // for it below. if (typicalMethod.IsGenericMethodDefinition || typicalMethod.OwningType.IsGenericDefinition) { dependencies ??= new DependencyList(); dependencies.Add(factory.ReflectableMethod(typicalMethod), reason); } // If there's any genericness involved, try to create a fitting instantiation that would be usable at runtime. // This is not a complete solution to the problem. // If we ever decide that MakeGenericType/MakeGenericMethod should simply be considered unsafe, this code can be deleted // and instantiations that are not fully closed can be ignored. if (method.OwningType.IsGenericDefinition || method.OwningType.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true)) { TypeDesc owningType = method.OwningType.GetTypeDefinition(); Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(owningType.Instantiation, allowCanon: false); if (inst.IsNull) { return(false); } method = method.Context.GetMethodForInstantiatedType( method.GetTypicalMethodDefinition(), ((MetadataType)owningType).MakeInstantiatedType(inst)); } if (method.IsGenericMethodDefinition || method.Instantiation.ContainsSignatureVariables()) { method = method.GetMethodDefinition(); Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(method.Instantiation, allowCanon: false); if (inst.IsNull) { return(false); } method = method.MakeInstantiatedMethod(inst); } try { // Make sure we're not putting something into the graph that will crash later. LibraryRootProvider.CheckCanGenerateMethod(method); } catch (TypeSystemException) { return(false); } dependencies ??= new DependencyList(); dependencies.Add(factory.ReflectableMethod(method), reason); return(true); }
public static bool TryGetDependenciesForReflectedField(ref DependencyList dependencies, NodeFactory factory, FieldDesc field, string reason) { // If there's any genericness involved, try to create a fitting instantiation that would be usable at runtime. // This is not a complete solution to the problem. // If we ever decide that MakeGenericType/MakeGenericMethod should simply be considered unsafe, this code can be deleted // and instantiations that are not fully closed can be ignored. if (field.OwningType.IsGenericDefinition || field.OwningType.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true)) { TypeDesc owningType = field.OwningType.GetTypeDefinition(); Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(owningType.Instantiation, allowCanon: true); if (inst.IsNull) { return(false); } field = field.Context.GetFieldForInstantiatedType( field.GetTypicalFieldDefinition(), ((MetadataType)owningType).MakeInstantiatedType(inst)); } if (factory.MetadataManager.IsReflectionBlocked(field)) { return(false); } if (!TryGetDependenciesForReflectedType(ref dependencies, factory, field.OwningType, reason)) { return(false); } // Currently generating the base of the type is enough to make the field reflectable. if (field.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) { return(true); } if (field.IsStatic && !field.IsLiteral && !field.HasRva) { bool cctorContextAdded = false; if (field.IsThreadStatic) { dependencies.Add(factory.TypeThreadStaticIndex((MetadataType)field.OwningType), reason); } else if (field.HasGCStaticBase) { dependencies.Add(factory.TypeGCStaticsSymbol((MetadataType)field.OwningType), reason); } else { dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)field.OwningType), reason); cctorContextAdded = true; } if (!cctorContextAdded && factory.PreinitializationManager.HasLazyStaticConstructor(field.OwningType)) { dependencies.Add(factory.TypeNonGCStaticsSymbol((MetadataType)field.OwningType), reason); } } return(true); }
public static void RootType(IRootingServiceProvider rootProvider, TypeDesc type, string reason) { rootProvider.AddCompilationRoot(type, reason); // Instantiate generic types over something that will be useful at runtime if (type.IsGenericDefinition) { Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: true); if (inst.IsNull) { return; } type = ((MetadataType)type).MakeInstantiatedType(inst); rootProvider.AddCompilationRoot(type, reason); } // Also root base types. This is so that we make methods on the base types callable. // This helps in cases like "class Foo : Bar<int> { }" where we discover new // generic instantiations. TypeDesc baseType = type.BaseType; if (baseType != null) { RootType(rootProvider, baseType.NormalizeInstantiation(), reason); } if (type.IsDefType) { bool hasFinalizer = type.HasFinalizer || type.IsObject; foreach (var method in type.GetMethods()) { // We don't root finalizers because they're not directly callable and they will get // generated if needed. We also need to prevent a VirtualMethodUse of Object::Finalize // from entering the system. if (hasFinalizer && method.IsFinalizer) { continue; } if (method.HasInstantiation) { // Generic methods on generic types could end up as Foo<object>.Bar<__Canon>(), // so for simplicity, we just don't handle them right now to make this more // predictable. if (!method.OwningType.HasInstantiation) { Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(method.Instantiation, allowCanon: false); if (!inst.IsNull) { TryRootMethod(rootProvider, method.MakeInstantiatedMethod(inst), reason); } } } else { TryRootMethod(rootProvider, method, reason); } } } }