public static bool IsVariantMethodCall(NodeFactory factory, MethodDesc calledMethod)
        {
            Debug.Assert(calledMethod.IsVirtual);

            TypeDesc owningType = calledMethod.OwningType;

            if (!owningType.IsInterface)
            {
                return(false);
            }

            bool result = false;

            if (owningType.HasVariance)
            {
                TypeDesc owningTypeDefinition = owningType.GetTypeDefinition();
                for (int i = 0; i < owningTypeDefinition.Instantiation.Length; i++)
                {
                    var variantParameter = (GenericParameterDesc)owningTypeDefinition.Instantiation[i];
                    if (variantParameter.Variance != 0)
                    {
                        // Variant interface parameters that are instantiated over valuetypes are
                        // not actually variant. Neither are contravariant parameters instantiated
                        // over sealed types (there won't be another interface castable to it
                        // through variance on that parameter).
                        TypeDesc variantArgument = owningType.Instantiation[i];
                        if (!variantArgument.IsValueType &&
                            (!variantArgument.IsSealed() || variantParameter.IsCovariant))
                        {
                            result = true;
                            break;
                        }
                    }
                }
            }

            if (!result && factory.TypeSystemContext.IsGenericArrayInterfaceType(owningType))
            {
                // 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 = owningType.Instantiation[0];
                result =
                    CastingHelper.IsArrayElementTypeCastableBySize(elementType) ||
                    (elementType.IsDefType && !elementType.IsValueType);
            }

            return(result);
        }
        public static bool IsVariantInterfaceImplementation(NodeFactory factory, TypeDesc providingType, DefType implementedInterface)
        {
            Debug.Assert(implementedInterface.IsInterface);
            Debug.Assert(!implementedInterface.IsGenericDefinition);

            // 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. IEnumerable<object>.GetEnumerator()
            // can dispatch to an implementation of IEnumerable<string>.GetEnumerator()).
            bool result = false;

            if (implementedInterface.HasVariance)
            {
                TypeDesc interfaceDefinition = implementedInterface.GetTypeDefinition();
                for (int i = 0; i < interfaceDefinition.Instantiation.Length; i++)
                {
                    var variantParameter = (GenericParameterDesc)interfaceDefinition.Instantiation[i];
                    if (variantParameter.Variance != 0)
                    {
                        // Variant interface parameters that are instantiated over valuetypes are
                        // not actually variant. Neither are contravariant parameters instantiated
                        // over sealed types (there won't be another interface castable to it
                        // through variance on that parameter).
                        TypeDesc variantArgument = implementedInterface.Instantiation[i];
                        if (!variantArgument.IsValueType &&
                            (!variantArgument.IsSealed() || variantParameter.IsCovariant))
                        {
                            result = true;
                            break;
                        }
                    }
                }
            }

            if (!result &&
                (providingType.IsArray || providingType.GetTypeDefinition() == factory.ArrayOfTEnumeratorType) &&
                implementedInterface.HasInstantiation)
            {
                // 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 = providingType.IsArray ? ((ArrayType)providingType).ElementType : providingType.Instantiation[0];
                result =
                    CastingHelper.IsArrayElementTypeCastableBySize(elementType) ||
                    (elementType.IsDefType && !elementType.IsValueType);
            }

            return(result);
        }
Esempio n. 3
0
        bool IsAssignable(TypeDesc src, TypeDesc dst, bool allowSizeEquivalence = false)
        {
            if (src == dst)
            {
                return(true);
            }

            if (src.IsValueType || dst.IsValueType)
            {
                if (allowSizeEquivalence && IsSameReducedType(src, dst))
                {
                    return(true);
                }

                // TODO IsEquivalent
                return(false);
            }

            return(CastingHelper.CanCastTo(src, dst));
        }
Esempio n. 4
0
        bool IsAssignable(StackValue src, StackValue dst)
        {
            if (src.Kind == dst.Kind && src.Type == dst.Type)
            {
                return(true);
            }

            if (dst.Type == null)
            {
                return(false);
            }

            switch (src.Kind)
            {
            case StackValueKind.ObjRef:
                if (dst.Kind != StackValueKind.ObjRef)
                {
                    return(false);
                }

                // null is always assignable
                if (src.Type == null)
                {
                    return(true);
                }

                return(CastingHelper.CanCastTo(src.Type, dst.Type));

            case StackValueKind.ValueType:

                // TODO: Other cases - variance, etc.

                return(false);

            case StackValueKind.ByRef:

                // TODO: Other cases - variance, etc.

                return(false);

            case StackValueKind.Int32:
                return(dst.Kind == StackValueKind.Int64 || dst.Kind == StackValueKind.NativeInt);

            case StackValueKind.Int64:
                return(false);

            case StackValueKind.NativeInt:
                return(dst.Kind == StackValueKind.Int64);

            case StackValueKind.Float:
                return(false);

            default:
                // TODO:
                // return false;
                throw new NotImplementedException();
            }

#if false
            if (child == parent)
            {
                return(TRUE);
            }

            // Normally we just let the runtime sort it out but we wish to be more strict
            // than the runtime wants to be.  For backwards compatibility, the runtime considers
            // int32[] and nativeInt[] to be the same on 32-bit machines.  It also is OK with
            // int64[] and nativeInt[] on a 64-bit machine.

            if (child.IsType(TI_REF) && parent.IsType(TI_REF) &&
                jitInfo->isSDArray(child.GetClassHandleForObjRef()) &&
                jitInfo->isSDArray(parent.GetClassHandleForObjRef()))
            {
                BOOL runtime_OK;

                // never be more lenient than the runtime
                runtime_OK = jitInfo->canCast(child.m_cls, parent.m_cls);
                if (!runtime_OK)
                {
                    return(false);
                }

                CORINFO_CLASS_HANDLE handle;
                CorInfoType          pType = jitInfo->getChildType(child.GetClassHandleForObjRef(), &handle);
                CorInfoType          cType = jitInfo->getChildType(parent.GetClassHandleForObjRef(), &handle);

                // don't care whether it is signed
                if (cType == CORINFO_TYPE_NATIVEUINT)
                {
                    cType = CORINFO_TYPE_NATIVEINT;
                }
                if (pType == CORINFO_TYPE_NATIVEUINT)
                {
                    pType = CORINFO_TYPE_NATIVEINT;
                }

                if (cType == CORINFO_TYPE_NATIVEINT)
                {
                    return(pType == CORINFO_TYPE_NATIVEINT);
                }

                if (pType == CORINFO_TYPE_NATIVEINT)
                {
                    return(cType == CORINFO_TYPE_NATIVEINT);
                }

                return(runtime_OK);
            }

            if (parent.IsUnboxedGenericTypeVar() || child.IsUnboxedGenericTypeVar())
            {
                return(FALSE); // need to have had child == parent
            }
            else if (parent.IsType(TI_REF))
            {
                // An uninitialized objRef is not compatible to initialized.
                if (child.IsUninitialisedObjRef() && !parent.IsUninitialisedObjRef())
                {
                    return(FALSE);
                }

                if (child.IsNullObjRef())           // NULL can be any reference type
                {
                    return(TRUE);
                }
                if (!child.IsType(TI_REF))
                {
                    return(FALSE);
                }

                return(jitInfo->canCast(child.m_cls, parent.m_cls));
            }
            else if (parent.IsType(TI_METHOD))
            {
                if (!child.IsType(TI_METHOD))
                {
                    return(FALSE);
                }

                // Right now we don't bother merging method handles
                return(FALSE);
            }
            else if (parent.IsType(TI_STRUCT))
            {
                if (!child.IsType(TI_STRUCT))
                {
                    return(FALSE);
                }

                // Structures are compatible if they are equivalent
                return(jitInfo->areTypesEquivalent(child.m_cls, parent.m_cls));
            }
            else if (parent.IsByRef())
            {
                return(tiCompatibleWithByRef(jitInfo, child, parent));
            }

            return(FALSE);
#endif
        }
Esempio n. 5
0
        private void AddVirtualMethodUseDependencies(DependencyList dependencyList, NodeFactory factory)
        {
            if (_type.RuntimeInterfaces.Length > 0 && !factory.VTable(_type).HasFixedSlots)
            {
                DefType closestDefType = _type.GetClosestDefType();

                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");
                            }
                        }
                    }
                }
            }
        }
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");

            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);
        }