Esempio n. 1
0
        internal static unsafe void UnhandledExceptionFailFastViaClasslib(
            RhFailFastReason reason, object unhandledException, IntPtr classlibAddress, ref ExInfo exInfo)
        {
            IntPtr pFailFastFunction =
                (IntPtr)InternalCalls.RhpGetClasslibFunctionFromCodeAddress(classlibAddress, ClassLibFunctionId.FailFast);

            if (pFailFastFunction == IntPtr.Zero)
            {
                FailFastViaClasslib(
                    reason,
                    unhandledException,
                    classlibAddress);
            }

            // 16-byte align the context.  This is overkill on x86 and ARM, but simplifies things slightly.
            const int contextAlignment = 16;
            byte *    pbBuffer         = stackalloc byte[sizeof(OSCONTEXT) + contextAlignment];
            void *    pContext         = PointerAlign(pbBuffer, contextAlignment);

            InternalCalls.RhpCopyContextFromExInfo(pContext, sizeof(OSCONTEXT), exInfo._pExContext);

            try
            {
                CalliIntrinsics.CallVoid(pFailFastFunction, reason, unhandledException, exInfo._pExContext->IP, (IntPtr)pContext);
            }
            catch when(true)
            {
                // disallow all exceptions leaking out of callbacks
            }

            // The classlib's funciton should never return and should not throw. If it does, then we fail our way...
            FallbackFailFast(reason, unhandledException);
        }
Esempio n. 2
0
        // Given an address pointing somewhere into a managed module, get the classlib-defined fail-fast
        // function and invoke it.  Any failure to find and invoke the function, or if it returns, results in
        // MRT-defined fail-fast behavior.
        internal static void FailFastViaClasslib(RhFailFastReason reason, object unhandledException,
                                                 IntPtr classlibAddress)
        {
            // Find the classlib function that will fail fast. This is a RuntimeExport function from the
            // classlib module, and is therefore managed-callable.
            IntPtr pFailFastFunction = (IntPtr)InternalCalls.RhpGetClasslibFunction(classlibAddress,
                                                                                    ClassLibFunctionId.FailFast);

            if (pFailFastFunction == IntPtr.Zero)
            {
                // The classlib didn't provide a function, so we fail our way...
                FallbackFailFast(reason, unhandledException);
            }

            try
            {
                // Invoke the classlib fail fast function.
                CalliIntrinsics.CallVoid(pFailFastFunction, reason, unhandledException, IntPtr.Zero, IntPtr.Zero);
            }
            catch
            {
                // disallow all exceptions leaking out of callbacks
            }

            // The classlib's function should never return and should not throw. If it does, then we fail our way...
            FallbackFailFast(reason, unhandledException);
        }
Esempio n. 3
0
        private static void AppendExceptionStackFrameViaClasslib(object exception, IntPtr IP,
                                                                 ref bool isFirstRethrowFrame, ref bool isFirstFrame)
        {
            IntPtr pAppendStackFrame = (IntPtr)InternalCalls.RhpGetClasslibFunction(IP,
                                                                                    ClassLibFunctionId.AppendExceptionStackFrame);

            if (pAppendStackFrame != IntPtr.Zero)
            {
                int flags = (isFirstFrame ? (int)RhEHFrameType.RH_EH_FIRST_FRAME : 0) |
                            (isFirstRethrowFrame ? (int)RhEHFrameType.RH_EH_FIRST_RETHROW_FRAME : 0);

                try
                {
                    CalliIntrinsics.CallVoid(pAppendStackFrame, exception, IP, flags);
                }
                catch
                {
                    // disallow all exceptions leaking out of callbacks
                }

                // Clear flags only if we called the function
                isFirstRethrowFrame = false;
                isFirstFrame        = false;
            }
        }
Esempio n. 4
0
        // Given an address pointing somewhere into a managed module, get the classlib-defined fail-fast
        // function and invoke it.  Any failure to find and invoke the function, or if it returns, results in
        // Rtm-define fail-fast behavior.
        internal unsafe static void FailFastViaClasslib(RhFailFastReason reason, Exception unhandledException,
                                                        IntPtr classlibAddress)
        {
            // Find the classlib function that will fail fast. This is a RuntimeExport function from the
            // classlib module, and is therefore managed-callable.
            IntPtr pFailFastFunction = (IntPtr)InternalCalls.RhpGetClasslibFunction(classlibAddress,
                                                                                    ClassLibFunctionId.FailFast);

            if (pFailFastFunction == IntPtr.Zero)
            {
                // The classlib didn't provide a function, so we fail our way...
                FailFast(reason, unhandledException);
            }

            try
            {
                // Invoke the classlib fail fast function.
                CalliIntrinsics.CallVoid(pFailFastFunction, reason, unhandledException, IntPtr.Zero);
            }
            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'.
            }

            // The classlib's funciton should never return and should not throw. If it does, then we fail our way...
            FailFast(reason, unhandledException);
        }
Esempio n. 5
0
        // 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);
        }
Esempio n. 6
0
        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);
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
#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);
        }
Esempio n. 9
0
        // Each class library can sign up for a callback to run code on the finalizer thread before any
        // objects derived from that class library's System.Object are finalized.  This is where we make those
        // callbacks.  When a class library is loaded, we set the s_fHasNewClasslibs flag and then the next
        // time the finalizer runs, we call this function to make any outstanding callbacks.
        private unsafe static void MakeFinalizerInitCallbacks()
        {
            while (true)
            {
                IntPtr pfnFinalizerInitCallback = InternalCalls.RhpGetNextFinalizerInitCallback();
                if (pfnFinalizerInitCallback == IntPtr.Zero)
                {
                    break;
                }

                CalliIntrinsics.CallVoid(pfnFinalizerInitCallback);
            }
        }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
        private unsafe static void DrainQueue()
        {
            // Drain the queue of finalizable objects.
            while (true)
            {
                Object target = InternalCalls.RhpGetNextFinalizableObject();
                if (target == null)
                {
                    return;
                }

                // Call the finalizer on the current target object. If the finalizer throws we'll fail
                // fast via normal Redhawk exception semantics (since we don't attempt to catch
                // anything).
                CalliIntrinsics.CallVoid(target.EEType->FinalizerCode, target);
            }
        }
Esempio n. 12
0
        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;
        }
Esempio n. 13
0
        internal unsafe static void UnhandledExceptionFailFastViaClasslib(
            RhFailFastReason reason, Exception unhandledException, ref ExInfo exInfo)
        {
            IntPtr pFailFastFunction = (IntPtr)InternalCalls.RhpGetClasslibFunction(exInfo._pExContext->IP,
                                                                                    ClassLibFunctionId.FailFast);

            if (pFailFastFunction == IntPtr.Zero)
            {
                FailFastViaClasslib(
                    reason,
                    unhandledException,
                    exInfo._pExContext->IP);
            }

            // 16-byte align the context.  This is overkill on x86 and ARM, but simplifies things slightly.
            const int contextAlignment = 16;
            byte *    pbBuffer         = stackalloc byte[sizeof(OSCONTEXT) + contextAlignment];
            void *    pContext         = PointerAlign(pbBuffer, contextAlignment);

            // We 'normalized' the faulting IP of hardware faults to behave like return addresses.  Undo this
            // normalization here so that we report the correct thing in the exception context record.
            if ((exInfo._kind & ExKind.KindMask) == ExKind.HardwareFault)
            {
                exInfo._pExContext->IP = (IntPtr)(((byte *)exInfo._pExContext->IP) - c_IPAdjustForHardwareFault);
            }

            InternalCalls.RhpCopyContextFromExInfo(pContext, sizeof(OSCONTEXT), exInfo._pExContext);

            try
            {
                CalliIntrinsics.CallVoid(pFailFastFunction, reason, unhandledException, (IntPtr)pContext);
            }
            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'.
            }

            // The classlib's funciton should never return and should not throw. If it does, then we fail our way...
            FailFast(reason, unhandledException);
        }
Esempio n. 14
0
        private static void OnFirstChanceExceptionViaClassLib(object exception)
        {
            IntPtr pOnFirstChanceFunction =
                (IntPtr)InternalCalls.RhpGetClasslibFunctionFromEEType((IntPtr)exception.m_pEEType, ClassLibFunctionId.OnFirstChance);

            if (pOnFirstChanceFunction == IntPtr.Zero)
            {
                return;
            }

            try
            {
                CalliIntrinsics.CallVoid(pOnFirstChanceFunction, exception);
            }
            catch when(true)
            {
                // disallow all exceptions leaking out of callbacks
            }
        }
Esempio n. 15
0
        internal unsafe static void AppendExceptionStackFrameViaClasslib(
            Exception exception, IntPtr IP, bool isFirstRethrowFrame, IntPtr classlibAddress, bool isFirstFrame)
        {
            IntPtr pAppendStackFrame = (IntPtr)InternalCalls.RhpGetClasslibFunction(classlibAddress,
                                                                                    ClassLibFunctionId.AppendExceptionStackFrame);
            int flags = (isFirstFrame ? (int)RhEHFrameType.RH_EH_FIRST_FRAME : 0) |
                        (isFirstRethrowFrame ? (int)RhEHFrameType.RH_EH_FIRST_RETHROW_FRAME : 0);

            if (pAppendStackFrame != IntPtr.Zero)
            {
                try
                {
                    CalliIntrinsics.CallVoid(pAppendStackFrame, exception, IP, flags);
                }
                catch
                {
                    // disallow all exceptions leaking out of callbacks
                }
            }
        }
Esempio n. 16
0
        public static void ProcessFinalizers()
        {
            while (true)
            {
                // Wait until there's some work to be done. If true is returned we should finalize objects,
                // otherwise memory is low and we should initiate a collection.
                if (InternalCalls.RhpWaitForFinalizerRequest() != 0)
                {
                    if (s_fHaveNewClasslibs)
                    {
                        s_fHaveNewClasslibs = false;
                        MakeFinalizerInitCallbacks();
                    }

                    // Drain the queue of finalizable objects.
                    Object target = InternalCalls.RhpGetNextFinalizableObject();
                    while (target != null)
                    {
                        // Call the finalizer on the current target object. If the finalizer throws we'll fail
                        // fast via normal Redhawk exception semantics (since we don't attempt to catch
                        // anything).
                        unsafe
                        {
                            CalliIntrinsics.CallVoid(target.EEType->FinalizerCode, target);
                        }

                        target = InternalCalls.RhpGetNextFinalizableObject();
                    }

                    // Tell anybody that's interested that the finalization pass is complete (there is a race condition here
                    // where we might immediately signal a new request as complete, but this is acceptable).
                    InternalCalls.RhpSignalFinalizationComplete();
                }
                else
                {
                    // RhpWaitForFinalizerRequest() returned false and indicated that memory is low. We help
                    // out by initiating a garbage collection and then go back to waiting for another request.
                    InternalCalls.RhCollect(-1, InternalGCCollectionMode.Blocking);
                }
            }
        }
Esempio n. 17
0
        internal unsafe static void UnhandledExceptionFailFastViaClasslib(
            RhFailFastReason reason, object unhandledException, IntPtr classlibAddress, ref ExInfo exInfo)
        {
            IntPtr pFailFastFunction =
                (IntPtr)InternalCalls.RhpGetClasslibFunction(classlibAddress, ClassLibFunctionId.FailFast);

            if (pFailFastFunction == IntPtr.Zero)
            {
                FailFastViaClasslib(
                    reason,
                    unhandledException,
                    classlibAddress);
            }

            // 16-byte align the context.  This is overkill on x86 and ARM, but simplifies things slightly.
            const int contextAlignment = 16;
            byte *    pbBuffer         = stackalloc byte[sizeof(OSCONTEXT) + contextAlignment];
            void *    pContext         = PointerAlign(pbBuffer, contextAlignment);

            // We 'normalized' the faulting IP of hardware faults to behave like return addresses.  Undo this
            // normalization here so that we report the correct thing in the exception context record.
            if ((exInfo._kind & ExKind.KindMask) == ExKind.HardwareFault)
            {
                exInfo._pExContext->IP = (IntPtr)(((byte *)exInfo._pExContext->IP) - c_IPAdjustForHardwareFault);
            }

            InternalCalls.RhpCopyContextFromExInfo(pContext, sizeof(OSCONTEXT), exInfo._pExContext);

            try
            {
                CalliIntrinsics.CallVoid(pFailFastFunction, reason, unhandledException, exInfo._pExContext->IP, (IntPtr)pContext);
            }
            catch
            {
                // disallow all exceptions leaking out of callbacks
            }

            // The classlib's funciton should never return and should not throw. If it does, then we fail our way...
            FallbackFailFast(reason, unhandledException);
        }
Esempio n. 18
0
        internal unsafe static void AppendExceptionStackFrameViaClasslib(
            Exception exception, IntPtr IP, bool isFirstRethrowFrame, IntPtr classlibAddress, bool isFirstFrame)
        {
            IntPtr pAppendStackFrame = (IntPtr)InternalCalls.RhpGetClasslibFunction(classlibAddress,
                                                                                    ClassLibFunctionId.AppendExceptionStackFrame);
            int flags = (isFirstFrame ? (int)RhEHFrameType.RH_EH_FIRST_FRAME : 0) |
                        (isFirstRethrowFrame ? (int)RhEHFrameType.RH_EH_FIRST_RETHROW_FRAME : 0);

            if (pAppendStackFrame != IntPtr.Zero)
            {
                try
                {
                    CalliIntrinsics.CallVoid(pAppendStackFrame, exception, IP, flags);
                }
                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'.
                }
            }
        }
Esempio n. 19
0
        // 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);
            }
        }
Esempio n. 20
0
        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
            }
        }