private static IntPtr RhResolveDispatchWorker(object pObject, EEType* pInterfaceType, ushort slot)
        {
            // Type of object we're dispatching on.
            EEType* pInstanceType = pObject.EEType;

            // Type whose DispatchMap is used. Usually the same as the above but for types which implement ICastable
            // we may repeat this process with an alternate type.
            EEType* pResolvingInstanceType = pInstanceType;

            IntPtr pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pResolvingInstanceType,
                                                                          pInterfaceType,
                                                                          slot);

            if (pTargetCode == IntPtr.Zero && pInstanceType->IsICastable)
            {
                // Dispatch not resolved through normal dispatch map, try using the ICastable
                IntPtr pfnGetImplTypeMethod = pInstanceType->ICastableGetImplTypeMethod;
                pResolvingInstanceType = (EEType*)CalliIntrinsics.Call<IntPtr>(pfnGetImplTypeMethod, pObject, new IntPtr(pInterfaceType));

                pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pResolvingInstanceType,
                                                                         pInterfaceType,
                                                                         slot);
            }

            return pTargetCode;
        }
Example #2
0
        private static bool FindImplSlotForCurrentType(EEType* pTgtType,
                                        EEType* pItfType,
                                        UInt16 itfSlotNumber,
                                        UInt16* pImplSlotNumber)
        {
            bool fRes = false;

            // If making a call and doing virtual resolution don't look into the dispatch map,
            // take the slot number directly.
            if (!pItfType->IsInterface)
            {
                *pImplSlotNumber = itfSlotNumber;

                // Only notice matches if the target type and search types are the same
                // This will make dispatch to sealed slots work correctly
                return pTgtType == pItfType;
            }

            if (pTgtType->HasDispatchMap)
            {
                // For variant interface dispatch, the algorithm is to walk the parent hierarchy, and at each level
                // attempt to dispatch exactly first, and then if that fails attempt to dispatch variantly. This can
                // result in interesting behavior such as a derived type only overriding one particular instantiation
                // and funneling all the dispatches to it, but its the algorithm.

                bool fDoVariantLookup = false; // do not check variance for first scan of dispatch map 

                fRes = FindImplSlotInSimpleMap(
                    pTgtType, pItfType, itfSlotNumber, pImplSlotNumber, fDoVariantLookup);

                if (!fRes)
                {
                    fDoVariantLookup = true; // check variance for second scan of dispatch map
                    fRes = FindImplSlotInSimpleMap(
                     pTgtType, pItfType, itfSlotNumber, pImplSlotNumber, fDoVariantLookup);
                }
            }

            return fRes;
        }
Example #3
0
#pragma warning restore

        public static IntPtr FindInterfaceMethodImplementationTarget(EEType* pTgtType,
                                                                 EEType* pItfType,
                                                                 ushort itfSlotNumber)
        {
            // Start at the current type and work up the inheritance chain
            EEType* pCur = pTgtType;
            UInt32 iCurInheritanceChainDelta = 0;

            if (pItfType->IsCloned)
                pItfType = pItfType->CanonicalEEType;

            while (pCur != null)
            {
                UInt16 implSlotNumber;
                if (FindImplSlotForCurrentType(
                        pCur, pItfType, itfSlotNumber, &implSlotNumber))
                {
                    IntPtr targetMethod;
                    if (implSlotNumber < pCur->NumVTableSlots)
                    {
                        // true virtual - need to get the slot from the target type in case it got overridden
                        targetMethod = pTgtType->GetVTableStartAddress()[implSlotNumber];
                    }
                    else
                    {
                        // sealed virtual - need to get the slot form the implementing type, because
                        // it's not present on the target type
                        targetMethod = pCur->GetSealedVirtualSlot((ushort)(implSlotNumber - pCur->NumVTableSlots));
                    }
                    return targetMethod;
                }
                if (pCur->IsArray)
                    pCur = pCur->ArrayBaseType;
                else
                    pCur = pCur->NonArrayBaseType;
                iCurInheritanceChainDelta++;
            }
            return IntPtr.Zero;
        }
Example #4
0
        // Method to compare two types pointers for type equality
        // We cannot just compare the pointers as there can be duplicate type instances
        // for cloned and constructed types.
        // There are three separate cases here
        //   1. The pointers are Equal => true
        //   2. Either one or both the types are CLONED, follow to the canonical EEType and check
        //   3. For Arrays/Pointers, we have to further check for rank and element type equality
        static private unsafe bool AreTypesEquivalentInternal(EEType* pType1, EEType* pType2)
        {
            if (pType1 == pType2)
                return true;

            if (pType1->IsCloned)
                pType1 = pType1->CanonicalEEType;

            if (pType2->IsCloned)
                pType2 = pType2->CanonicalEEType;

            if (pType1 == pType2)
                return true;

            if (pType1->IsParameterizedType && pType2->IsParameterizedType)
                return AreTypesEquivalentInternal(pType1->RelatedParameterType, pType2->RelatedParameterType) && pType1->ParameterizedTypeShape == pType2->ParameterizedTypeShape;

            return false;
        }
Example #5
0
        // Internally callable version of the export method above. Has two additional parameters:
        //  fBoxedSource            : assume the source type is boxed so that value types and enums are
        //                            compatible with Object, ValueType and Enum (if applicable)
        //  fAllowSizeEquivalence   : allow identically sized integral types and enums to be considered
        //                            equivalent (currently used only for array element types)
        static internal unsafe bool AreTypesAssignableInternal(EEType* pSourceType, EEType* pTargetType, bool fBoxedSource, bool fAllowSizeEquivalence)
        {
            //
            // Are the types identical?
            //
            if (AreTypesEquivalentInternal(pSourceType, pTargetType))
                return true;

            //
            // Handle cast to interface cases.
            //
            if (pTargetType->IsInterface)
            {
                // Value types can only be cast to interfaces if they're boxed.
                if (!fBoxedSource && pSourceType->IsValueType)
                    return false;

                if (ImplementsInterface(pSourceType, pTargetType))
                    return true;

                // Are the types compatible due to generic variance?
                if (pTargetType->HasGenericVariance && pSourceType->HasGenericVariance)
                    return TypesAreCompatibleViaGenericVariance(pSourceType, pTargetType);

                return false;
            }
            if (pSourceType->IsInterface)
            {
                // The only non-interface type an interface can be cast to is Object.
                return WellKnownEETypes.IsSystemObject(pTargetType);
            }

            //
            // Handle cast to array or pointer cases.
            //
            if (pTargetType->IsParameterizedType)
            {
                if (pSourceType->IsParameterizedType && (pTargetType->ParameterizedTypeShape == pSourceType->ParameterizedTypeShape))
                {
                    // Source type is also a parameterized type. Are the parameter types compatible? Note that using
                    // AreTypesAssignableInternal here handles array covariance as well as IFoo[] -> Foo[]
                    // etc. Pass false for fBoxedSource since int[] is not assignable to object[].
                    if (pSourceType->RelatedParameterType->IsPointerTypeDefinition)
                    {
                        // If the parameter types are pointers, then only exact matches are correct.
                        // As we've already called AreTypesEquivalent at the start of this function,
                        // return false as the exact match case has already been handled.
                        // int** is not compatible with uint**, nor is int*[] oompatible with uint*[].
                        return false;
                    }
                    else
                    {
                        return AreTypesAssignableInternal(pSourceType->RelatedParameterType, pTargetType->RelatedParameterType, false, true);
                    }
                }

                // Can't cast a non-parameter type to a parameter type or a parameter type of different shape to a parameter type
                return false;
            }
            if (pSourceType->IsArray)
            {
                // Target type is not an array. But we can still cast arrays to Object or System.Array.
                return WellKnownEETypes.IsSystemObject(pTargetType) || WellKnownEETypes.IsSystemArray(pTargetType);
            }
            else if (pSourceType->IsParameterizedType)
            {
                return false;
            }

            //
            // Handle cast to other (non-interface, non-array) cases.
            //

            if (pSourceType->IsValueType)
            {
                // Certain value types of the same size are treated as equivalent when the comparison is
                // between array element types (indicated by fAllowSizeEquivalence). These are integer types
                // of the same size (e.g. int and uint) and the base type of enums vs all integer types of the
                // same size.
                if (fAllowSizeEquivalence && pTargetType->IsValueType)
                {
                    if (ArePrimitveTypesEquivalentSize(pSourceType, pTargetType))
                        return true;

                    // Non-identical value types aren't equivalent in any other case (since value types are
                    // sealed).
                    return false;
                }

                // If the source type is a value type but it's not boxed then we've run out of options: the types
                // are not identical, the target type isn't an interface and we're not allowed to check whether
                // the target type is a parent of this one since value types are sealed and thus the only matches
                // would be against Object, ValueType or Enum, all of which are reference types and not compatible
                // with non-boxed value types.
                if (!fBoxedSource)
                    return false;
            }

            // Sub case of casting between two instantiations of the same delegate type where one or more of
            // the type parameters have variance. Only interfaces and delegate types can have variance over
            // their type parameters and we know that neither type is an interface due to checks above.
            if (pTargetType->HasGenericVariance && pSourceType->HasGenericVariance)
            {
                // We've dealt with the identical case at the start of this method. And the regular path below
                // will handle casting to Object, Delegate and MulticastDelegate. Since we don't support
                // deriving from user delegate classes any further all we have to check here is that the
                // uninstantiated generic delegate definitions are the same and the type parameters are
                // compatible.
                return TypesAreCompatibleViaGenericVariance(pSourceType, pTargetType);
            }

            // Is the source type derived from the target type?
            if (IsDerived(pSourceType, pTargetType))
                return true;

            return false;
        }
Example #6
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;
        }
Example #7
0
            public unsafe static bool AreTypesAssignableInternal(EEType* pSourceType, EEType* pTargetType, AssignmentVariation variation)
            {
                // Important special case -- it breaks infinite recursion in CastCache itself!
                if (pSourceType == pTargetType)
                    return true;

                Key key = new Key(pSourceType, pTargetType, variation);
                Entry entry = LookupInCache(s_cache, ref key);
                if (entry == null)
                    return CacheMiss(ref key);

                return entry.Result;
            }
Example #8
0
 internal unsafe extern static object RhpNewFastMisalign(EEType * pEEType);
Example #9
0
 internal unsafe extern static object RhpNewFinalizableAlign8(EEType* pEEType);
Example #10
0
 internal unsafe extern static void RhpGetDispatchCellInfo(IntPtr pCell, EEType** pInterfaceType, ushort* slot);
Example #11
0
 internal unsafe extern static IntPtr RhpGetSealedVirtualSlot(EEType* pEEType, ushort slot);
Example #12
0
 internal unsafe extern static DispatchResolve.DispatchMap* RhpGetDispatchMap(EEType* pEEType);
Example #13
0
 internal unsafe extern static bool RhpHasDispatchMap(EEType* pEETypen);
Example #14
0
 internal unsafe extern static EEType* RhpGetArrayBaseType(EEType* pEEType);
Example #15
0
 internal unsafe extern static void RhUnbox(object obj, void* pData, EEType* pUnboxToEEType);
Example #16
0
 internal extern static unsafe IntPtr RhpGetICastableGetImplTypeMethod(EEType* pEEType);
Example #17
0
 internal unsafe extern static object RhpNewFastAlign8(EEType * pEEType);  // BEWARE: not for finalizable objects!
Example #18
0
 internal unsafe extern static IntPtr RhpSearchDispatchCellCache(IntPtr pCell, EEType* pInstanceType);
Example #19
0
 internal unsafe extern static object RhpNewArrayAlign8(EEType* pEEType, int length);
Example #20
0
 internal unsafe extern static IntPtr RhpUpdateDispatchCellCache(IntPtr pCell, IntPtr pTargetCode, EEType* pInstanceType);
Example #21
0
                public Key(EEType* pSourceType, EEType* pTargetType, AssignmentVariation variation)
                {
                    Debug.Assert((((long)pSourceType) & 3) == 0, "misaligned EEType!");
                    Debug.Assert(((uint)variation) <= 3, "variation enum has an unexpectedly large value!");

                    _sourceTypeAndVariation = (IntPtr)(((byte*)pSourceType) + ((int)variation));
                    _targetType = (IntPtr)pTargetType;
                }
Example #22
0
 internal extern static unsafe EEType* RhGetGenericInstantiation(EEType* pEEType,
                                                                  int* pArity,
                                                                  EETypeRef** ppInstantiation,
                                                                  GenericVariance** ppVarianceInfo);
Example #23
0
 unsafe static bool IsInstanceOfInterfaceViaICastable(object obj, EEType* pTargetType)
 {
     // Call the ICastable.IsInstanceOfInterface method directly rather than via an interface
     // dispatch since we know the method address statically. We ignore any cast error exception
     // object passed back on failure (result == false) since IsInstanceOfInterface never throws.
     IntPtr pfnIsInstanceOfInterface = obj.EEType->ICastableIsInstanceOfInterfaceMethod;
     Exception castError = null;
     if (CalliIntrinsics.Call<bool>(pfnIsInstanceOfInterface, obj, pTargetType, out castError))
         return true;
     return false;
 }
Example #24
0
 internal extern static unsafe UInt32 RhpGetEETypeRareFlags(EEType* pEEType);
Example #25
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;
        }
Example #26
0
 internal extern static unsafe byte RhpGetNullableEETypeValueOffset(EEType* pEEType);
Example #27
0
        static internal unsafe bool IsDerived(EEType* pDerivedType, EEType* pBaseType)
        {
            Debug.Assert(!pDerivedType->IsArray, "did not expect array type");
            Debug.Assert(!pDerivedType->IsParameterizedType, "did not expect parameterType");
            Debug.Assert(!pBaseType->IsArray, "did not expect array type");
            Debug.Assert(!pBaseType->IsInterface, "did not expect interface type");
            Debug.Assert(!pBaseType->IsParameterizedType, "did not expect parameterType");
            Debug.Assert(pBaseType->IsCanonical || pBaseType->IsCloned || pBaseType->IsGenericTypeDefinition, "unexpected eetype");
            Debug.Assert(pDerivedType->IsCanonical || pDerivedType->IsCloned || pDerivedType->IsGenericTypeDefinition, "unexpected eetype");

            // If a generic type definition reaches this function, then the function should return false unless the types are equivalent.
            // This works as the NonClonedNonArrayBaseType of a GenericTypeDefinition is always null.

            if (pBaseType->IsCloned)
                pBaseType = pBaseType->CanonicalEEType;

            do
            {
                if (pDerivedType->IsCloned)
                    pDerivedType = pDerivedType->CanonicalEEType;

                if (pDerivedType == pBaseType)
                    return true;

                pDerivedType = pDerivedType->NonClonedNonArrayBaseType;
            }
            while (pDerivedType != null);

            return false;
        }
Example #28
0
 internal extern static unsafe EEType* RhpGetNullableEEType(EEType* pEEType);
Example #29
0
        // Returns true of the two types are equivalent primitive types. Used by array casts.
        static private unsafe bool ArePrimitveTypesEquivalentSize(EEType* pType1, EEType* pType2)
        {
            CorElementType sourceCorType = pType1->CorElementType;
            int sourcePrimitiveTypeEquivalenceSize = GetIntegralTypeMatchSize(sourceCorType);

            // Quick check to see if the first type is even primitive.
            if (sourcePrimitiveTypeEquivalenceSize == 0)
                return false;

            CorElementType targetCorType = pType2->CorElementType;
            int targetPrimitiveTypeEquivalenceSize = GetIntegralTypeMatchSize(targetCorType);

            return sourcePrimitiveTypeEquivalenceSize == targetPrimitiveTypeEquivalenceSize;
        }
Example #30
0
 internal extern static unsafe IntPtr RhpGetICastableIsInstanceOfInterfaceMethod(EEType* pEEType);