Exemplo n.º 1
0
        // Returns an address in the module most closely associated with this EEType that can be handed to
        // EH.GetClasslibException and use to locate the compute the correct exception type. In most cases
        // this is just the EEType pointer itself, but when this type represents a generic that has been
        // unified at runtime (and thus the EEType pointer resides in the process heap rather than a specific
        // module) we need to do some work.
        internal unsafe IntPtr GetAssociatedModuleAddress()
        {
            fixed(EEType *pThis = &this)
            {
                if (!IsRuntimeAllocated && !IsDynamicType)
                {
                    return((IntPtr)pThis);
                }

                // There are currently three types of runtime allocated EETypes, arrays, pointers, and generic types.
                // Arrays/Pointers can be handled by looking at their element type.
                if (IsParameterizedType)
                {
                    return(pThis->RelatedParameterType->GetAssociatedModuleAddress());
                }

                // Generic types are trickier. Often we could look at the parent type (since eventually it
                // would derive from the class library's System.Object which is definitely not runtime
                // allocated). But this breaks down for generic interfaces. Instead we fetch the generic
                // instantiation information and use the generic type definition, which will always be module
                // local. We know this lookup will succeed since we're dealing with a unified generic type
                // and the unification process requires this metadata.
                EETypeRef *      pInstantiation;
                int              arity;
                GenericVariance *pVarianceInfo;
                EEType *         pGenericType = InternalCalls.RhGetGenericInstantiation(pThis,
                                                                                        &arity,
                                                                                        &pInstantiation,
                                                                                        &pVarianceInfo);

                Debug.Assert(pGenericType != null, "Generic type expected");

                return((IntPtr)pGenericType);
            }
        }
Exemplo n.º 2
0
        // Compare two types to see if they are compatible via generic variance.
        static private unsafe bool TypesAreCompatibleViaGenericVariance(EEType *pSourceType, EEType *pTargetType)
        {
            // Get generic instantiation metadata for both types.

            EETypeRef *      pTargetInstantiation;
            int              targetArity;
            GenericVariance *pTargetVarianceInfo;
            EEType *         pTargetGenericType = InternalCalls.RhGetGenericInstantiation(pTargetType,
                                                                                          &targetArity,
                                                                                          &pTargetInstantiation,
                                                                                          &pTargetVarianceInfo);

            Debug.Assert(pTargetVarianceInfo != null, "did not expect empty variance info");

            EETypeRef *      pSourceInstantiation;
            int              sourceArity;
            GenericVariance *pSourceVarianceInfo;
            EEType *         pSourceGenericType = InternalCalls.RhGetGenericInstantiation(pSourceType,
                                                                                          &sourceArity,
                                                                                          &pSourceInstantiation,
                                                                                          &pSourceVarianceInfo);

            Debug.Assert(pSourceVarianceInfo != null, "did not expect empty variance info");

            // If the generic types aren't the same then the types aren't compatible.
            if (pSourceGenericType == pTargetGenericType)
            {
                // The types represent different instantiations of the same generic type. The
                // arity of both had better be the same.
                Debug.Assert(targetArity == sourceArity, "arity mismatch betweeen generic instantiations");

                // Compare the instantiations to see if they're compatible taking variance into account.
                if (TypeParametersAreCompatible(targetArity,
                                                pSourceInstantiation,
                                                pTargetInstantiation,
                                                pTargetVarianceInfo,
                                                false))
                {
                    return(true);
                }
            }

            return(false);
        }
Exemplo n.º 3
0
        static internal unsafe bool ImplementsInterface(EEType *pObjType, EEType *pTargetType)
        {
            Debug.Assert(!pTargetType->IsParameterizedType, "did not expect paramterized type");
            Debug.Assert(pTargetType->IsInterface, "IsInstanceOfInterface called with non-interface EEType");

            // This can happen with generic interface types
            // Debug.Assert(!pTargetType->IsCloned, "cloned interface types are disallowed");

            // canonicalize target type
            if (pTargetType->IsCloned)
            {
                pTargetType = pTargetType->CanonicalEEType;
            }

            int numInterfaces             = pObjType->NumInterfaces;
            EEInterfaceInfo *interfaceMap = pObjType->InterfaceMap;

            for (int i = 0; i < numInterfaces; i++)
            {
                EEType *pInterfaceType = interfaceMap[i].InterfaceType;

                // canonicalize the interface type
                if (pInterfaceType->IsCloned)
                {
                    pInterfaceType = pInterfaceType->CanonicalEEType;
                }

                if (pInterfaceType == pTargetType)
                {
                    return(true);
                }
            }

            // We did not find the interface type in the list of supported interfaces. There's still one
            // chance left: if the target interface is generic and one or more of its type parameters is co or
            // contra variant then the object can still match if it implements a different instantiation of
            // the interface with type compatible generic arguments.
            //
            // An additional edge case occurs because of array covariance. This forces us to treat any generic
            // interfaces implemented by arrays as covariant over their one type parameter.
            bool fArrayCovariance = pObjType->IsArray;

            if (pTargetType->HasGenericVariance || (fArrayCovariance && pTargetType->IsGeneric))
            {
                // Grab details about the instantiation of the target generic interface.
                EETypeRef *      pTargetInstantiation;
                int              targetArity;
                GenericVariance *pTargetVarianceInfo;
                EEType *         pTargetGenericType = InternalCalls.RhGetGenericInstantiation(pTargetType,
                                                                                              &targetArity,
                                                                                              &pTargetInstantiation,
                                                                                              &pTargetVarianceInfo);

                Debug.Assert(pTargetVarianceInfo != null, "did not expect empty variance info");


                for (int i = 0; i < numInterfaces; i++)
                {
                    EEType *pInterfaceType = interfaceMap[i].InterfaceType;

                    // We can ignore interfaces which are not also marked as having generic variance
                    // unless we're dealing with array covariance.
                    if (pInterfaceType->HasGenericVariance || (fArrayCovariance && pInterfaceType->IsGeneric))
                    {
                        // Grab instantiation details for the candidate interface.
                        EETypeRef *      pInterfaceInstantiation;
                        int              interfaceArity;
                        GenericVariance *pInterfaceVarianceInfo;
                        EEType *         pInterfaceGenericType = InternalCalls.RhGetGenericInstantiation(pInterfaceType,
                                                                                                         &interfaceArity,
                                                                                                         &pInterfaceInstantiation,
                                                                                                         &pInterfaceVarianceInfo);

                        Debug.Assert(pInterfaceVarianceInfo != null, "did not expect empty variance info");

                        // If the generic types aren't the same then the types aren't compatible.
                        if (pInterfaceGenericType != pTargetGenericType)
                        {
                            continue;
                        }

                        // The types represent different instantiations of the same generic type. The
                        // arity of both had better be the same.
                        Debug.Assert(targetArity == interfaceArity, "arity mismatch betweeen generic instantiations");

                        // Compare the instantiations to see if they're compatible taking variance into account.
                        if (TypeParametersAreCompatible(targetArity,
                                                        pInterfaceInstantiation,
                                                        pTargetInstantiation,
                                                        pTargetVarianceInfo,
                                                        fArrayCovariance))
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Exemplo n.º 4
0
        private static bool FindImplSlotInSimpleMap(EEType *pTgtType,
                                                    EEType *pItfType,
                                                    UInt32 itfSlotNumber,
                                                    UInt16 *pImplSlotNumber,
                                                    bool actuallyCheckVariance)
        {
            Debug.Assert(pTgtType->HasDispatchMap, "Missing dispatch map");

            EEType *         pItfOpenGenericType = null;
            EETypeRef *      pItfInstantiation   = null;
            int              itfArity            = 0;
            GenericVariance *pItfVarianceInfo    = null;

            bool fCheckVariance   = false;
            bool fArrayCovariance = false;

            if (actuallyCheckVariance)
            {
                fCheckVariance   = pItfType->HasGenericVariance;
                fArrayCovariance = pTgtType->IsArray;

                // Non-arrays can follow array variance rules iff
                // 1. They have one generic parameter
                // 2. That generic parameter is array covariant.
                //
                // This special case is to allow array enumerators to work
                if (!fArrayCovariance && pTgtType->HasGenericVariance)
                {
                    EETypeRef *      pTgtInstantiation;
                    int              tgtEntryArity;
                    GenericVariance *pTgtVarianceInfo;
                    EEType *         pTgtEntryGenericType = InternalCalls.RhGetGenericInstantiation(pTgtType,
                                                                                                    &tgtEntryArity,
                                                                                                    &pTgtInstantiation,
                                                                                                    &pTgtVarianceInfo);

                    if ((tgtEntryArity == 1) && pTgtVarianceInfo[0] == GenericVariance.ArrayCovariant)
                    {
                        fArrayCovariance = true;
                    }
                }

                // Arrays are covariant even though you can both get and set elements (type safety is maintained by
                // runtime type checks during set operations). This extends to generic interfaces implemented on those
                // arrays. We handle this by forcing all generic interfaces on arrays to behave as though they were
                // covariant (over their one type parameter corresponding to the array element type).
                if (fArrayCovariance && pItfType->IsGeneric)
                {
                    fCheckVariance = true;
                }

                // If there is no variance checking, there is no operation to perform. (The non-variance check loop
                // has already completed)
                if (!fCheckVariance)
                {
                    return(false);
                }
            }

            DispatchMap *     pMap = pTgtType->DispatchMap;
            DispatchMapEntry *i    = &pMap->_dispatchMap;
            DispatchMapEntry *iEnd = (&pMap->_dispatchMap) + pMap->_entryCount;

            for (; i != iEnd; ++i)
            {
                if (i->_usInterfaceMethodSlot == itfSlotNumber)
                {
                    EEType *pCurEntryType =
                        pTgtType->InterfaceMap[i->_usInterfaceIndex].InterfaceType;

                    if (pCurEntryType->IsCloned)
                    {
                        pCurEntryType = pCurEntryType->CanonicalEEType;
                    }

                    if (pCurEntryType == pItfType)
                    {
                        *pImplSlotNumber = i->_usImplMethodSlot;
                        return(true);
                    }
                    else if (fCheckVariance && ((fArrayCovariance && pCurEntryType->IsGeneric) || pCurEntryType->HasGenericVariance))
                    {
                        // Interface types don't match exactly but both the target interface and the current interface
                        // in the map are marked as being generic with at least one co- or contra- variant type
                        // parameter. So we might still have a compatible match.

                        // Retrieve the unified generic instance for the callsite interface if we haven't already (we
                        // lazily get this then cache the result since the lookup isn't necessarily cheap).
                        if (pItfOpenGenericType == null)
                        {
                            pItfOpenGenericType = InternalCalls.RhGetGenericInstantiation(pItfType,
                                                                                          &itfArity,
                                                                                          &pItfInstantiation,
                                                                                          &pItfVarianceInfo);
                        }

                        // Retrieve the unified generic instance for the interface we're looking at in the map.
                        // Grab instantiation details for the candidate interface.
                        EETypeRef *      pCurEntryInstantiation;
                        int              curEntryArity;
                        GenericVariance *pCurEntryVarianceInfo;
                        EEType *         pCurEntryGenericType = InternalCalls.RhGetGenericInstantiation(pCurEntryType,
                                                                                                        &curEntryArity,
                                                                                                        &pCurEntryInstantiation,
                                                                                                        &pCurEntryVarianceInfo);

                        // If the generic types aren't the same then the types aren't compatible.
                        if (pItfOpenGenericType != pCurEntryGenericType)
                        {
                            continue;
                        }

                        // The types represent different instantiations of the same generic type. The
                        // arity of both had better be the same.
                        Debug.Assert(itfArity == curEntryArity, "arity mismatch betweeen generic instantiations");

                        if (TypeCast.TypeParametersAreCompatible(itfArity, pCurEntryInstantiation, pItfInstantiation, pItfVarianceInfo, fArrayCovariance))
                        {
                            *pImplSlotNumber = i->_usImplMethodSlot;
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }