private static void AddDependenciesDueToCustomAttributes(ref DependencyList dependencies, NodeFactory factory, EcmaModule module, CustomAttributeHandleCollection attributeHandles)
        {
            MetadataReader  reader                = module.MetadataReader;
            MetadataManager mdManager             = factory.MetadataManager;
            var             attributeTypeProvider = new CustomAttributeTypeProvider(module);


            foreach (CustomAttributeHandle caHandle in attributeHandles)
            {
                CustomAttribute attribute = reader.GetCustomAttribute(caHandle);

                try
                {
                    MethodDesc constructor = module.GetMethod(attribute.Constructor);
                    if (mdManager.IsReflectionBlocked(constructor))
                    {
                        continue;
                    }

                    // Make a new list in case we need to abort.
                    var caDependencies = new DependencyList();

                    caDependencies.Add(factory.CanonicalEntrypoint(constructor), "Attribute constructor");
                    caDependencies.Add(factory.ConstructedTypeSymbol(constructor.OwningType), "Attribute type");

                    CustomAttributeValue <TypeDesc> decodedValue = attribute.DecodeValue(attributeTypeProvider);

                    if (AddDependenciesFromCustomAttributeBlob(caDependencies, factory, constructor.OwningType, decodedValue))
                    {
                        dependencies = dependencies ?? new DependencyList();
                        dependencies.AddRange(caDependencies);
                    }
                }
                catch (TypeSystemException)
                {
                    // We could end up seeing an exception here for a multitude of reasons:
                    // * Attribute ctor doesn't resolve
                    // * There's a typeof() that refers to something that can't be loaded
                    // * Attribute refers to a non-existing field
                    // * Etc.
                    //
                    // If we really wanted to, we could probably come up with a way to still make this
                    // work with the same failure modes at runtime as the CLR, but it might not be
                    // worth the hassle: the input was invalid. The most important thing is that we
                    // don't crash the compilation.
                }
            }
        }
        private static bool AddDependenciesFromPropertySetter(DependencyList dependencies, NodeFactory factory, TypeDesc attributeType, string propertyName)
        {
            EcmaType attributeTypeDefinition = (EcmaType)attributeType.GetTypeDefinition();

            MetadataReader reader         = attributeTypeDefinition.MetadataReader;
            var            typeDefinition = reader.GetTypeDefinition(attributeTypeDefinition.Handle);

            foreach (PropertyDefinitionHandle propDefHandle in typeDefinition.GetProperties())
            {
                PropertyDefinition propDef = reader.GetPropertyDefinition(propDefHandle);
                if (reader.StringComparer.Equals(propDef.Name, propertyName))
                {
                    PropertyAccessors accessors = propDef.GetAccessors();

                    if (!accessors.Setter.IsNil)
                    {
                        MethodDesc setterMethod = (MethodDesc)attributeTypeDefinition.EcmaModule.GetObject(accessors.Setter);
                        if (factory.MetadataManager.IsReflectionBlocked(setterMethod))
                        {
                            return(false);
                        }

                        // Method on a generic attribute
                        if (attributeType != attributeTypeDefinition)
                        {
                            setterMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(setterMethod, (InstantiatedType)attributeType);
                        }

                        // TODO: what if the setter is virtual/abstract?
                        dependencies.Add(factory.CanonicalEntrypoint(setterMethod), "Custom attribute blob");
                    }

                    return(true);
                }
            }

            // Haven't found it in current type. Check the base type.
            TypeDesc baseType = attributeType.BaseType;

            if (baseType != null)
            {
                return(AddDependenciesFromPropertySetter(dependencies, factory, baseType, propertyName));
            }

            // Not found. This is bad metadata that will result in a runtime failure, but we shouldn't fail the compilation.
            return(true);
        }
Esempio n. 3
0
        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);
        }
        private static void HandleCall(ref DependencyList list, NodeFactory factory, MethodIL methodIL, MethodDesc methodCalled, ref Tracker tracker)
        {
            switch (methodCalled.Name)
            {
            // Enum.GetValues(Type) needs array of that type
            case "GetValues" when methodCalled.OwningType == factory.TypeSystemContext.GetWellKnownType(WellKnownType.Enum):
            {
                TypeDesc type = tracker.GetLastType();
                if (type != null && type.IsEnum && !type.IsGenericDefinition /* generic enums! */)
                {
                    // Type could be something weird like MyEnum<object, __Canon> - normalize it
                    type = type.NormalizeInstantiation();

                    list = list ?? new DependencyList();
                    list.Add(factory.ConstructedTypeSymbol(type.MakeArrayType()), "Enum.GetValues");
                }
            }
            break;

            // Type.GetType(string...) needs the type with the given name
            case "GetType" when methodCalled.OwningType.IsSystemType() && methodCalled.Signature.Length > 0:
            {
                string name = tracker.GetLastString();
                if (name != null &&
                    methodIL.OwningMethod.OwningType is MetadataType mdType &&
                    ResolveType(name, mdType.Module, out TypeDesc type, out ModuleDesc referenceModule) &&
                    !factory.MetadataManager.IsReflectionBlocked(type))
                {
                    const string reason = "Type.GetType";
                    list = list ?? new DependencyList();
                    list.Add(factory.MaximallyConstructableType(type), reason);

                    // Also add module metadata in case this reference was through a type forward
                    if (factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType()))
                    {
                        list.Add(factory.ModuleMetadata(referenceModule), reason);
                    }

                    // Opportunistically remember the type so that it flows to Type.GetMethod if needed.
                    tracker.TrackType(type);
                }
            }
            break;

            // Type.GetMethod(string...)
            case "GetMethod" when methodCalled.OwningType.IsSystemType():
            {
                string   name = tracker.GetLastString();
                TypeDesc type = tracker.GetLastType();
                if (name != null &&
                    type != null &&
                    !factory.MetadataManager.IsReflectionBlocked(type))
                {
                    if (type.IsGenericDefinition)
                    {
                        Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: false);
                        if (inst.IsNull)
                        {
                            break;
                        }
                        type = ((MetadataType)type).MakeInstantiatedType(inst);
                        list = list ?? new DependencyList();
                        list.Add(factory.MaximallyConstructableType(type), "Type.GetMethod");
                    }
                    else
                    {
                        // Type could be something weird like SomeType<object, __Canon> - normalize it
                        type = type.NormalizeInstantiation();
                    }

                    MethodDesc reflectedMethod = type.GetMethod(name, null);
                    if (reflectedMethod != null &&
                        !factory.MetadataManager.IsReflectionBlocked(reflectedMethod))
                    {
                        if (reflectedMethod.HasInstantiation)
                        {
                            // Don't want to accidentally get Foo<__Canon>.Bar<object>()
                            if (reflectedMethod.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
                            {
                                break;
                            }

                            Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(reflectedMethod.Instantiation, allowCanon: false);
                            if (inst.IsNull)
                            {
                                break;
                            }
                            reflectedMethod = reflectedMethod.MakeInstantiatedMethod(inst);
                        }

                        const string reason = "Type.GetMethod";
                        list = list ?? new DependencyList();
                        if (reflectedMethod.IsVirtual)
                        {
                            RootVirtualMethodForReflection(ref list, factory, reflectedMethod, reason);
                        }

                        if (!reflectedMethod.IsAbstract)
                        {
                            list.Add(factory.CanonicalEntrypoint(reflectedMethod), reason);
                            if (reflectedMethod.HasInstantiation &&
                                reflectedMethod != reflectedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific))
                            {
                                list.Add(factory.MethodGenericDictionary(reflectedMethod), reason);
                            }
                        }
                    }
                }
            }
            break;

            case "SizeOf" when IsMarshalSizeOf(methodCalled):
            {
                TypeDesc type = tracker.GetLastType();
                if (IsTypeEligibleForMarshalSizeOfTracking(type))
                {
                    list = list ?? new DependencyList();

                    list.Add(factory.StructMarshallingData((DefType)type), "Marshal.SizeOf");
                }
            }
            break;
            }
        }
Esempio n. 5
0
        private static void HandleTypeGetMethod(ref DependencyList list, NodeFactory factory, TypeDesc type, string name, string reason)
        {
            if (factory.MetadataManager.IsReflectionBlocked(type))
            {
                return;
            }

            if (type.IsGenericDefinition)
            {
                Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: false);
                if (inst.IsNull)
                {
                    return;
                }
                type = ((MetadataType)type).MakeInstantiatedType(inst);
                list = list ?? new DependencyList();
                list.Add(factory.MaximallyConstructableType(type), reason);
            }
            else
            {
                // Type could be something weird like SomeType<object, __Canon> - normalize it
                type = type.NormalizeInstantiation();
            }

            MethodDesc reflectedMethod = type.GetMethod(name, null);

            if (reflectedMethod != null &&
                !factory.MetadataManager.IsReflectionBlocked(reflectedMethod))
            {
                if (reflectedMethod.HasInstantiation)
                {
                    // Don't want to accidentally get Foo<__Canon>.Bar<object>()
                    if (reflectedMethod.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
                    {
                        return;
                    }

                    Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(reflectedMethod.Instantiation, allowCanon: false);
                    if (inst.IsNull)
                    {
                        return;
                    }
                    reflectedMethod = reflectedMethod.MakeInstantiatedMethod(inst);
                }

                list = list ?? new DependencyList();
                if (reflectedMethod.IsVirtual)
                {
                    RootVirtualMethodForReflection(ref list, factory, reflectedMethod, reason);
                }

                if (!reflectedMethod.IsAbstract)
                {
                    list.Add(factory.CanonicalEntrypoint(reflectedMethod), reason);
                    if (reflectedMethod.HasInstantiation &&
                        reflectedMethod != reflectedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific))
                    {
                        list.Add(factory.MethodGenericDictionary(reflectedMethod), reason);
                    }
                }
            }
        }
Esempio n. 6
0
        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");

            if (_type is MetadataType mdType &&
                mdType.Module.GetGlobalModuleType().GetStaticConstructor() is MethodDesc moduleCctor)
            {
                dependencyList.Add(factory.MethodEntrypoint(moduleCctor), "Type in a module with initializer");
            }

            DefType closestDefType = _type.GetClosestDefType();

            if (MightHaveInterfaceDispatchMap(factory))
            {
                dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map");
            }

            if (_type.IsArray)
            {
                // Array MethodTable 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");
                    }
                }
            }

            // 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.CanonicalEntrypoint(defaultCtor),
                                       "DefaultConstructorNode"));
            }

            return(dependencyList);
        }
        private static void HandleCall(ref DependencyList list, NodeFactory factory, MethodIL methodIL, MethodDesc methodCalled, ref Tracker tracker)
        {
            switch (methodCalled.Name)
            {
            // Enum.GetValues(Type) needs array of that type
            case "GetValues" when methodCalled.OwningType == factory.TypeSystemContext.GetWellKnownType(WellKnownType.Enum):
            {
                TypeDesc type = tracker.GetLastType();
                if (type != null && type.IsEnum && !type.IsGenericDefinition /* generic enums! */)
                {
                    list = list ?? new DependencyList();
                    list.Add(factory.ConstructedTypeSymbol(type.MakeArrayType()), "Enum.GetValues");
                }
            }
            break;

            // Type.GetType(string...) needs the type with the given name
            case "GetType" when methodCalled.OwningType.IsSystemType() && methodCalled.Signature.Length > 0:
            {
                string name = tracker.GetLastString();
                if (name != null &&
                    methodIL.OwningMethod.OwningType is MetadataType mdType &&
                    ResolveType(name, mdType.Module, out TypeDesc type, out ModuleDesc referenceModule) &&
                    !factory.MetadataManager.IsReflectionBlocked(type))
                {
                    const string reason = "Type.GetType";
                    list = list ?? new DependencyList();
                    list.Add(factory.MaximallyConstructableType(type), reason);

                    // Also add module metadata in case this reference was through a type forward
                    if (factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType()))
                    {
                        list.Add(factory.ModuleMetadata(referenceModule), reason);
                    }

                    // Opportunistically remember the type so that it flows to Type.GetMethod if needed.
                    tracker.TrackType(type);
                }
            }
            break;

            // Type.GetMethod(string...)
            case "GetMethod" when methodCalled.OwningType.IsSystemType():
            {
                string   name = tracker.GetLastString();
                TypeDesc type = tracker.GetLastType();
                if (name != null &&
                    type != null &&
                    !factory.MetadataManager.IsReflectionBlocked(type))
                {
                    if (type.IsGenericDefinition)
                    {
                        Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: false);
                        if (inst.IsNull)
                        {
                            break;
                        }
                        type = ((MetadataType)type).MakeInstantiatedType(inst);
                        list = list ?? new DependencyList();
                        list.Add(factory.MaximallyConstructableType(type), "Type.GetMethod");
                    }

                    MethodDesc reflectedMethod = type.GetMethod(name, null);
                    if (reflectedMethod != null &&
                        !factory.MetadataManager.IsReflectionBlocked(reflectedMethod))
                    {
                        if (reflectedMethod.HasInstantiation)
                        {
                            // Don't want to accidentally get Foo<__Canon>.Bar<object>()
                            if (reflectedMethod.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
                            {
                                break;
                            }

                            Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(reflectedMethod.Instantiation, allowCanon: false);
                            if (inst.IsNull)
                            {
                                break;
                            }
                            reflectedMethod = reflectedMethod.MakeInstantiatedMethod(inst);
                        }

                        const string reason = "Type.GetMethod";
                        list = list ?? new DependencyList();
                        if (reflectedMethod.IsVirtual)
                        {
                            RootVirtualMethodForReflection(ref list, factory, reflectedMethod, reason);
                        }

                        if (!reflectedMethod.IsAbstract)
                        {
                            list.Add(factory.CanonicalEntrypoint(reflectedMethod), reason);
                            if (reflectedMethod.HasInstantiation &&
                                reflectedMethod != reflectedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific))
                            {
                                list.Add(factory.MethodGenericDictionary(reflectedMethod), reason);
                            }
                        }
                    }
                }
            }
            break;

            case "SizeOf" when methodCalled.OwningType.IsSystemRuntimeInteropServicesMarshal() && !methodCalled.HasInstantiation &&
                methodCalled.Signature.Length == 1 && methodCalled.Signature[0].IsSystemType():
            {
                TypeDesc type = tracker.GetLastType();
                if (type != null && !type.IsGenericDefinition && !type.IsCanonicalSubtype(CanonicalFormKind.Any))
                {
                    list = list ?? new DependencyList();

                    MethodDesc marshalSizeOfGeneric = methodCalled.OwningType.GetKnownMethod(
                        "SizeOf", new MethodSignature(MethodSignatureFlags.Static, 1, methodCalled.Context.GetWellKnownType(WellKnownType.Int32), TypeDesc.EmptyTypes));
                    marshalSizeOfGeneric = marshalSizeOfGeneric.MakeInstantiatedMethod(type);

                    // InteropManager is looking for the following method bodies or dictionaries to decide marshalling info need.
                    // We should ideally model these as separate entities in the dependency graph and add those entities instead.
                    // Fixable after https://github.com/dotnet/corert/issues/6063 is fixed.
                    if (marshalSizeOfGeneric.GetCanonMethodTarget(CanonicalFormKind.Specific) != marshalSizeOfGeneric)
                    {
                        list.Add(factory.MethodGenericDictionary(marshalSizeOfGeneric), "Marshal.SizeOf");
                    }
                    else
                    {
                        list.Add(factory.MethodEntrypoint(marshalSizeOfGeneric), "Marshal.SizeOf");
                    }
                }
            }
            break;
            }
        }