static public unsafe object IsInstanceOfInterface(object obj, void *pvTargetType) { if (obj == null) { return(null); } EEType *pTargetType = (EEType *)pvTargetType; EEType *pObjType = obj.EEType; if (ImplementsInterface(pObjType, pTargetType)) { return(obj); } // If object type implements ICastable then there's one more way to check whether it implements // the interface. if (pObjType->IsICastable) { // 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 = pObjType->ICastableIsInstanceOfInterfaceMethod; Exception castError = null; if (CalliIntrinsics.Call <bool>(pfnIsInstanceOfInterface, obj, pTargetType, out castError)) { return(obj); } } return(null); }
// Given an ExceptionID and an address pointing somewhere into a managed module, get // an exception object of a type that the module containing the given address will understand. // This finds the classlib-defined GetRuntimeException function and asks it for the exception object. internal static Exception GetClasslibException(ExceptionIDs id, IntPtr address) { // Find the classlib function that will give us the exception object we want to throw. This // is a RuntimeExport function from the classlib module, and is therefore managed-callable. IntPtr pGetRuntimeExceptionFunction = (IntPtr)InternalCalls.RhpGetClasslibFunction(address, ClassLibFunctionId.GetRuntimeException); // Return the exception object we get from the classlib. Exception e = null; try { e = CalliIntrinsics.Call <Exception>(pGetRuntimeExceptionFunction, id); } catch { // disallow all exceptions leaking out of callbacks } // If the helper fails to yield an object, then we fail-fast. if (e == null) { FailFastViaClasslib( RhFailFastReason.ClassLibDidNotTranslateExceptionID, null, address); } return(e); }
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); }
#pragma warning restore public static IntPtr FindInterfaceMethodImplementationTarget(EEType *pTgtType, EEType *pItfType, ushort itfSlotNumber) { DynamicModule *dynamicModule = pTgtType->DynamicModule; // Use the dynamic module resolver if it's present if ((dynamicModule != null) && (dynamicModule->DynamicTypeSlotDispatchResolve != IntPtr.Zero)) { return(CalliIntrinsics.Call <IntPtr>(dynamicModule->DynamicTypeSlotDispatchResolve, (IntPtr)pTgtType, (IntPtr)pItfType, 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->GetArrayEEType(); } else { pCur = pCur->NonArrayBaseType; } iCurInheritanceChainDelta++; } return(IntPtr.Zero); }
internal static unsafe IntPtr GetCastableObjectDispatchCellThunk(EEType *pInstanceType, IntPtr pDispatchCell) { IntPtr pTargetCode = CacheLookup(s_ThunkBasedDispatchCellTargets, pDispatchCell); if (pTargetCode != default(IntPtr)) { return(pTargetCode); } InternalCalls.RhpAcquireCastCacheLock(); { // Look in the cache again after taking the lock pTargetCode = CacheLookup(s_ThunkBasedDispatchCellTargets, pDispatchCell); if (pTargetCode != default(IntPtr)) { return(pTargetCode); } // Allocate a new thunk. Failure to allocate one will result in a fail-fast. We don't return nulls from this API. // TODO: The allocation of thunks here looks like a layering duck tape. The allocation of the raw // thunks should be a core runtime service (ie it should live in MRT). // Delete the callback logic once this moves to MRT. IntPtr pAllocateThunkFunction = (IntPtr)InternalCalls.RhpGetClasslibFunction( pInstanceType->GetAssociatedModuleAddress(), EH.ClassLibFunctionId.AllocateThunkWithData); pTargetCode = CalliIntrinsics.Call <IntPtr>( pAllocateThunkFunction, InternalCalls.RhpGetCastableObjectDispatch_CommonStub(), pDispatchCell, InternalCalls.RhpGetCastableObjectDispatchHelper_TailCalled()); if (pTargetCode == IntPtr.Zero) { EH.FallbackFailFast(RhFailFastReason.InternalError, null); } AddToThunkCache(pDispatchCell, pTargetCode); } InternalCalls.RhpReleaseCastCacheLock(); return(pTargetCode); }
static public /*internal*/ unsafe object CheckCastInterface(Object obj, void *pvTargetEEType) { // a null value can be cast to anything if (obj == null) { return(null); } EEType *pTargetType = (EEType *)pvTargetEEType; EEType *pObjType = obj.EEType; if (ImplementsInterface(pObjType, pTargetType)) { return(obj); } Exception castError = null; // If object type implements ICastable then there's one more way to check whether it implements // the interface. if (pObjType->IsICastable) { // Call the ICastable.IsInstanceOfInterface method directly rather than via an interface // dispatch since we know the method address statically. IntPtr pfnIsInstanceOfInterface = pObjType->ICastableIsInstanceOfInterfaceMethod; if (CalliIntrinsics.Call <bool>(pfnIsInstanceOfInterface, obj, pTargetType, out castError)) { return(obj); } } // Throw the invalid cast exception defined by the classlib, using the input EEType* to find the // correct classlib unless ICastable.IsInstanceOfInterface returned a more specific exception for // us to use. IntPtr addr = ((EEType *)pvTargetEEType)->GetAssociatedModuleAddress(); if (castError == null) { castError = EH.GetClasslibException(ExceptionIDs.InvalidCast, addr); } BinderIntrinsics.TailCall_RhpThrowEx(castError); throw castError; }
// Given an ExceptionID and an address pointing somewhere into a managed module, get // an exception object of a type that the module contianing the given address will understand. // This finds the classlib-defined GetRuntimeException function and asks it for the exception object. internal static Exception GetClasslibException(ExceptionIDs id, IntPtr address) { unsafe { // Find the classlib function that will give us the exception object we want to throw. This // is a RuntimeExport function from the classlib module, and is therefore managed-callable. void *pGetRuntimeExceptionFunction = InternalCalls.RhpGetClasslibFunction(address, ClassLibFunctionId.GetRuntimeException); // Return the exception object we get from the classlib. Exception e = null; try { e = CalliIntrinsics.Call <Exception>((IntPtr)pGetRuntimeExceptionFunction, id); } catch { // Unfortunately, this catch turns into "catch (System.Object)", which will not catch // exceptions thrown from the class library because their objects do not derive from our // System.Object. // // @TODO: Use a filtered catch whose filter always returns 'true'. } // If the helper fails to yield an object, then we fail-fast. if (e == null) { FailFastViaClasslib( RhFailFastReason.ClassLibDidNotTranslateExceptionID, null, address); } return(e); } }
private static unsafe IntPtr RhResolveDispatchWorker(object pObject, void *cell, ref DispatchCellInfo cellInfo) { // Type of object we're dispatching on. EEType *pInstanceType = pObject.EEType; if (cellInfo.CellType == DispatchCellType.InterfaceAndSlot) { // 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, cellInfo.InterfaceType.ToPointer(), cellInfo.InterfaceSlot); if (pTargetCode == IntPtr.Zero && pInstanceType->IsICastable) { // TODO!! BEGIN REMOVE THIS CODE WHEN WE REMOVE ICASTABLE // Dispatch not resolved through normal dispatch map, try using the ICastable // 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 = pInstanceType->ICastableIsInstanceOfInterfaceMethod; Exception castError = null; if (CalliIntrinsics.Call <bool>(pfnIsInstanceOfInterface, pObject, cellInfo.InterfaceType.ToPointer(), out castError)) { IntPtr pfnGetImplTypeMethod = pInstanceType->ICastableGetImplTypeMethod; pResolvingInstanceType = (EEType *)CalliIntrinsics.Call <IntPtr>(pfnGetImplTypeMethod, pObject, new IntPtr(cellInfo.InterfaceType.ToPointer())); pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pResolvingInstanceType, cellInfo.InterfaceType.ToPointer(), cellInfo.InterfaceSlot); } else // TODO!! END REMOVE THIS CODE WHEN WE REMOVE ICASTABLE { // Dispatch not resolved through normal dispatch map, using the CastableObject path pTargetCode = InternalCalls.RhpGetCastableObjectDispatchHelper(); } } return(pTargetCode); } else if (cellInfo.CellType == DispatchCellType.VTableOffset) { // Dereference VTable return(*(IntPtr *)(((byte *)pInstanceType) + cellInfo.VTableOffset)); } else { #if SUPPORTS_NATIVE_METADATA_TYPE_LOADING // Attempt to convert dispatch cell to non-metadata form if we haven't acquired a cache for this cell yet if (cellInfo.HasCache == 0) { cellInfo = InternalTypeLoaderCalls.ConvertMetadataTokenDispatch(InternalCalls.RhGetModuleFromPointer(cell), cellInfo); if (cellInfo.CellType != DispatchCellType.MetadataToken) { return(RhResolveDispatchWorker(pObject, cell, ref cellInfo)); } } // If that failed, go down the metadata resolution path return(InternalTypeLoaderCalls.ResolveMetadataTokenDispatch(InternalCalls.RhGetModuleFromPointer(cell), (int)cellInfo.MetadataToken, new IntPtr(pInstanceType))); #else EH.FallbackFailFast(RhFailFastReason.InternalError, null); return(IntPtr.Zero); #endif } }