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); }
// 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); }
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; } }
// 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); }
// 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); }
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); }
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); }
// 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); } }
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); }
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); } }
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; }
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); }
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 } }
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 } } }
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); } } }
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); }
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'. } } }
// 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 } }