private static unsafe bool UnboxAnyTypeCompare(EEType *pEEType, EEType *ptrUnboxToEEType)
        {
            if (TypeCast.AreTypesEquivalentInternal(pEEType, ptrUnboxToEEType))
            {
                return(true);
            }

            if (pEEType->CorElementType == ptrUnboxToEEType->CorElementType)
            {
                // Enum's and primitive types should pass the UnboxAny exception cases
                // if they have an exactly matching cor element type.
                switch (ptrUnboxToEEType->CorElementType)
                {
                case CorElementType.ELEMENT_TYPE_I1:
                case CorElementType.ELEMENT_TYPE_U1:
                case CorElementType.ELEMENT_TYPE_I2:
                case CorElementType.ELEMENT_TYPE_U2:
                case CorElementType.ELEMENT_TYPE_I4:
                case CorElementType.ELEMENT_TYPE_U4:
                case CorElementType.ELEMENT_TYPE_I8:
                case CorElementType.ELEMENT_TYPE_U8:
                case CorElementType.ELEMENT_TYPE_I:
                case CorElementType.ELEMENT_TYPE_U:
                    return(true);
                }
            }

            return(false);
        }
Exemple #2
0
        private static bool ShouldTypedClauseCatchThisException(object exception, EEType *pClauseType)
        {
            if (TypeCast.IsInstanceOfClass(exception, pClauseType) != null)
            {
                return(true);
            }

            if (s_pLowLevelObjectType == null)
            {
                // TODO: Avoid allocating here as that may fail
                s_pLowLevelObjectType = new System.Object().EEType;
            }

            // This allows the typical try { } catch { }--which expands to a typed catch of System.Object--to work on
            // all objects when the clause is in the low level runtime code.  This special case is needed because
            // objects from foreign type systems are sometimes throw back up at runtime code and this is the only way
            // to catch them outside of having a filter with no type check in it, which isn't currently possible to
            // write in C#.  See https://github.com/dotnet/roslyn/issues/4388
            if (pClauseType->IsEquivalentTo(s_pLowLevelObjectType))
            {
                return(true);
            }

            return(false);
        }
Exemple #3
0
        private static bool ShouldTypedClauseCatchThisException(object exception, EEType *pClauseType)
        {
#if DEBUG && !INPLACE_RUNTIME
            AssertNotRuntimeObject(pClauseType);
#endif

            return(TypeCast.IsInstanceOfClass(exception, pClauseType) != null);
        }
Exemple #4
0
        public static unsafe void RhUnboxNullable(ref byte data, EETypePtr pUnboxToEEType, Object obj)
        {
            EEType *ptrUnboxToEEType = (EEType *)pUnboxToEEType.ToPointer();

            if ((obj != null) && !TypeCast.AreTypesEquivalentInternal(obj.EEType, ptrUnboxToEEType->NullableType))
            {
                throw ptrUnboxToEEType->GetClasslibException(ExceptionIDs.InvalidCast);
            }
            InternalCalls.RhUnbox(obj, ref data, ptrUnboxToEEType);
        }
Exemple #5
0
        public unsafe static void RhUnboxAny(object o, ref Hack_o_p data, EETypePtr pUnboxToEEType)
        {
            EEType *ptrUnboxToEEType = (EEType *)pUnboxToEEType.ToPointer();

            if (ptrUnboxToEEType->IsValueType)
            {
                // HACK: we would really want to take the address of o here,
                // but the rules of the C# language don't let us do that,
                // so we arrive at the same result by taking the address of p
                // and going back one pointer-sized unit
                fixed(IntPtr *pData = &data.p)
                {
                    bool isValid = false;

                    if (ptrUnboxToEEType->IsNullable)
                    {
                        isValid = (o == null) || TypeCast.AreTypesEquivalentInternal(o.EEType, ptrUnboxToEEType->GetNullableType());
                    }
                    else if (o != null)
                    {
                        isValid = UnboxAnyTypeCompare(o.EEType, ptrUnboxToEEType);
                    }

                    if (!isValid)
                    {
                        // Throw the invalid cast exception defined by the classlib, using the input unbox EEType*
                        // to find the correct classlib.

                        ExceptionIDs exID = o == null ? ExceptionIDs.NullReference : ExceptionIDs.InvalidCast;

                        IntPtr    addr = ptrUnboxToEEType->GetAssociatedModuleAddress();
                        Exception e    = EH.GetClasslibException(exID, addr);

                        BinderIntrinsics.TailCall_RhpThrowEx(e);
                    }
                    InternalCalls.RhUnbox(o, pData - 1, ptrUnboxToEEType);
                }
            }
            else
            {
                if (o == null || (TypeCast.IsInstanceOf(o, ptrUnboxToEEType) != null))
                {
                    data.o = o;
                }
                else
                {
                    IntPtr    addr = ptrUnboxToEEType->GetAssociatedModuleAddress();
                    Exception e    = EH.GetClasslibException(ExceptionIDs.InvalidCast, addr);

                    BinderIntrinsics.TailCall_RhpThrowEx(e);
                }
            }
        }
Exemple #6
0
        public static unsafe void RhArrayStoreCheckAny(object array, ref byte data)
        {
            if (array == null)
            {
                return;
            }

            Debug.Assert(array.EEType->IsArray, "first argument must be an array");

            EEType *arrayElemType = array.EEType->RelatedParameterType;

            if (arrayElemType->IsValueType)
            {
                return;
            }

            TypeCast.CheckArrayStore(array, Unsafe.As <byte, Object>(ref data));
        }
Exemple #7
0
        static public /*internal*/ unsafe void RhArrayStoreCheckAny(object array, ref Hack_o_p data)
        {
            if (array == null)
            {
                return;
            }

            Debug.Assert(array.EEType->IsArray, "first argument must be an array");

            EEType *arrayElemType = array.EEType->RelatedParameterType;

            if (arrayElemType->IsValueType)
            {
                return;
            }

            TypeCast.CheckArrayStore(array, data.o);
        }
Exemple #8
0
        public static unsafe void RhUnboxAny(object o, ref byte data, EETypePtr pUnboxToEEType)
        {
            EEType *ptrUnboxToEEType = (EEType *)pUnboxToEEType.ToPointer();

            if (ptrUnboxToEEType->IsValueType)
            {
                bool isValid = false;

                if (ptrUnboxToEEType->IsNullable)
                {
                    isValid = (o == null) || TypeCast.AreTypesEquivalentInternal(o.EEType, ptrUnboxToEEType->NullableType);
                }
                else
                {
                    isValid = (o != null) && UnboxAnyTypeCompare(o.EEType, ptrUnboxToEEType);
                }

                if (!isValid)
                {
                    // Throw the invalid cast exception defined by the classlib, using the input unbox EEType*
                    // to find the correct classlib.

                    ExceptionIDs exID = o == null ? ExceptionIDs.NullReference : ExceptionIDs.InvalidCast;

                    throw ptrUnboxToEEType->GetClasslibException(exID);
                }

                InternalCalls.RhUnbox(o, ref data, ptrUnboxToEEType);
            }
            else
            {
                if (o != null && (TypeCast.IsInstanceOf(o, ptrUnboxToEEType) == null))
                {
                    throw ptrUnboxToEEType->GetClasslibException(ExceptionIDs.InvalidCast);
                }

                Unsafe.As <byte, Object>(ref data) = o;
            }
        }
Exemple #9
0
        private static bool FindImplSlotInSimpleMap(EEType *pTgtType,
                                                    EEType *pItfType,
                                                    uint itfSlotNumber,
                                                    ushort *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)
                {
                    int tgtEntryArity = (int)pTgtType->GenericArity;
                    GenericVariance *pTgtVarianceInfo = pTgtType->GenericVariance;

                    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;

            DispatchMap.DispatchMapEntry *i    = (*pMap)[0];
            DispatchMap.DispatchMapEntry *iEnd = (*pMap)[(int)pMap->NumEntries];
            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 = pItfType->GenericDefinition;
                            itfArity            = (int)pItfType->GenericArity;
                            pItfInstantiation   = pItfType->GenericArguments;
                            pItfVarianceInfo    = pItfType->GenericVariance;
                        }

                        // Retrieve the unified generic instance for the interface we're looking at in the map.
                        EEType *pCurEntryGenericType = pCurEntryType->GenericDefinition;

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

                        // Grab instantiation details for the candidate interface.
                        EETypeRef *pCurEntryInstantiation = pCurEntryType->GenericArguments;

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

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

            return(false);
        }