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); }
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); }
private static bool ShouldTypedClauseCatchThisException(object exception, EEType *pClauseType) { #if DEBUG && !INPLACE_RUNTIME AssertNotRuntimeObject(pClauseType); #endif return(TypeCast.IsInstanceOfClass(exception, pClauseType) != null); }
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); }
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); } } }
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)); }
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); }
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; } }
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); }