public static unsafe EETypePtr RhGetInterface(EETypePtr ptrEEType, uint index) { EEType *pEEType = ptrEEType.ToPointer(); // The convoluted pointer arithmetic into the interface map below (rather than a simply array // dereference) is because C# will generate a 64-bit multiply for the lookup by default. This // causes us a problem on x86 because it uses a helper that's mapped directly into the CRT via // import magic and that technique doesn't work with the way we link this code into the runtime // image. Since we don't need a 64-bit multiply here (the classlib is trusted code) we manually // perform the calculation. EEInterfaceInfo *pInfo = (EEInterfaceInfo *)((byte *)pEEType->InterfaceMap + (index * (uint)sizeof(EEInterfaceInfo))); return(new EETypePtr((IntPtr)pInfo->InterfaceType)); }
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); }