public static void RhRethrow(ref ExInfo activeExInfo, ref ExInfo exInfo) { // trigger a GC (only if gcstress) to ensure we can stackwalk at this point GCStress.TriggerGC(); InternalCalls.RhpValidateExInfoStack(); // We need to copy the Exception object to this stack location because collided unwinds will cause // the original stack location to go dead. Exception rethrownException = activeExInfo.ThrownException; exInfo.Init(rethrownException, ref activeExInfo); DispatchEx(ref exInfo._frameIter, ref exInfo, activeExInfo._idxCurClause); BinderIntrinsics.DebugBreak(); }
public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) { // trigger a GC (only if gcstress) to ensure we can stackwalk at this point GCStress.TriggerGC(); InternalCalls.RhpValidateExInfoStack(); IntPtr faultingCodeAddress = exInfo._pExContext->IP; ExceptionIDs exceptionId; switch (exceptionCode) { case (uint)HwExceptionCode.STATUS_REDHAWK_NULL_REFERENCE: exceptionId = ExceptionIDs.NullReference; break; case (uint)HwExceptionCode.STATUS_DATATYPE_MISALIGNMENT: exceptionId = ExceptionIDs.DataMisaligned; break; // N.B. -- AVs that have a read/write address lower than 64k are already transformed to // HwExceptionCode.REDHAWK_NULL_REFERENCE prior to calling this routine. case (uint)HwExceptionCode.STATUS_ACCESS_VIOLATION: exceptionId = ExceptionIDs.AccessViolation; break; case (uint)HwExceptionCode.STATUS_INTEGER_DIVIDE_BY_ZERO: exceptionId = ExceptionIDs.DivideByZero; break; default: // We don't wrap SEH exceptions from foreign code like CLR does, so we believe that we // know the complete set of HW faults generated by managed code and do not need to handle // this case. FailFastViaClasslib(RhFailFastReason.InternalError, null, faultingCodeAddress); exceptionId = ExceptionIDs.NullReference; break; } Exception exceptionToThrow = GetClasslibException(exceptionId, faultingCodeAddress); exInfo.Init(exceptionToThrow); DispatchEx(ref exInfo._frameIter, ref exInfo, MaxTryRegionIdx); BinderIntrinsics.DebugBreak(); }
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; }
public static IntPtr RhHandleAllocVariable(object value, uint type) { IntPtr h = InternalCalls.RhpHandleAllocVariable(value, type); if (h == IntPtr.Zero) { // Throw the out of memory exception defined by the classlib, using the return address of this method // to find the correct classlib. ExceptionIDs exID = ExceptionIDs.OutOfMemory; IntPtr returnAddr = BinderIntrinsics.GetReturnAddress(); Exception e = EH.GetClasslibException(exID, returnAddr); throw e; } return(h); }
public static IntPtr RhHandleAllocDependent(object primary, object secondary) { IntPtr h = InternalCalls.RhpHandleAllocDependent(primary, secondary); if (h == IntPtr.Zero) { // Throw the out of memory exception defined by the classlib, using the return address of this method // to find the correct classlib. ExceptionIDs exID = ExceptionIDs.OutOfMemory; IntPtr returnAddr = BinderIntrinsics.GetReturnAddress(); Exception e = EH.GetClasslibException(exID, returnAddr); throw e; } return(h); }
public static void RhThrowEx(Exception exceptionObj, ref ExInfo exInfo) { // trigger a GC (only if gcstress) to ensure we can stackwalk at this point GCStress.TriggerGC(); InternalCalls.RhpValidateExInfoStack(); // Transform attempted throws of null to a throw of NullReferenceException. if (exceptionObj == null) { IntPtr faultingCodeAddress = exInfo._pExContext->IP; exceptionObj = GetClasslibException(ExceptionIDs.NullReference, faultingCodeAddress); } exInfo.Init(exceptionObj); DispatchEx(ref exInfo._frameIter, ref exInfo, MaxTryRegionIdx); BinderIntrinsics.DebugBreak(); }
static public unsafe void RhUnboxNullable(ref Hack_o_p data, EETypePtr pUnboxToEEType, Object obj) { EEType *ptrUnboxToEEType = (EEType *)pUnboxToEEType.ToPointer(); // 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) { if ((obj != null) && (obj.EEType != ptrUnboxToEEType->GetNullableType())) { Exception e = ptrUnboxToEEType->GetClasslibException(ExceptionIDs.InvalidCast); BinderIntrinsics.TailCall_RhpThrowEx(e); } InternalCalls.RhUnbox(obj, pData - 1, ptrUnboxToEEType); } }
public static void RhpReversePInvokeBadTransition() { IntPtr returnAddress = BinderIntrinsics.GetReturnAddress(); if (returnAddress != IntPtr.Zero) { EH.FailFastViaClasslib( RhFailFastReason.IllegalNativeCallableEntry, null, returnAddress); } else { // @HACKHACK: we need to force the method to have an EBP frame so that we can use the // GetReturnAddress() intrinsic above. This seems to be the smallest way to do this. EH.FailFast(RhFailFastReason.InternalError, null); throw EH.GetClasslibException(ExceptionIDs.Arithmetic, returnAddress); } }
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) || (o.EEType == ptrUnboxToEEType->GetNullableType()); } else { isValid = (o != null && o.EEType->CorElementType == ptrUnboxToEEType->CorElementType && TypeCast.IsInstanceOfClass(o, ptrUnboxToEEType) != null); } 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 { data.o = o; } }
static public unsafe void *RhUnbox2(EETypePtr pUnboxToEEType, Object obj) { EEType *ptrUnboxToEEType = (EEType *)pUnboxToEEType.ToPointer(); if (obj.EEType != ptrUnboxToEEType) { // We allow enums and their primtive type to be interchangable if (obj.EEType->CorElementType != ptrUnboxToEEType->CorElementType) { Exception e = ptrUnboxToEEType->GetClasslibException(ExceptionIDs.InvalidCast); BinderIntrinsics.TailCall_RhpThrowEx(e); } } fixed(void *pObject = &obj.m_pEEType) { // CORERT-TODO: This code has GC hole - the method return type should really be byref. // Requires byref returns in C# to fix cleanly (https://github.com/dotnet/roslyn/issues/118) return((IntPtr *)pObject + 1); } }
static public /*internal*/ unsafe void CheckUnbox(Object obj, byte expectedCorElementType) { if (obj == null) { return; } if (obj.EEType->CorElementType == (CorElementType)expectedCorElementType) { return; } // Throw the invalid cast exception defined by the classlib, using the input object's EEType* // to find the correct classlib. ExceptionIDs exID = ExceptionIDs.InvalidCast; IntPtr addr = obj.EEType->GetAssociatedModuleAddress(); Exception e = EH.GetClasslibException(exID, addr); BinderIntrinsics.TailCall_RhpThrowEx(e); }
static public /*internal*/ unsafe void CheckArrayStore(object array, object obj) { if (array == null || obj == null) { return; } Debug.Assert(array.EEType->IsArray, "first argument must be an array"); EEType *arrayElemType = array.EEType->RelatedParameterType; bool compatible; if (arrayElemType->IsInterface) { compatible = IsInstanceOfInterface(obj, arrayElemType) != null; } else if (arrayElemType->IsArray) { compatible = IsInstanceOfArray(obj, arrayElemType) != null; } else { compatible = IsInstanceOfClass(obj, arrayElemType) != null; } if (!compatible) { // Throw the array type mismatch exception defined by the classlib, using the input array's EEType* // to find the correct classlib. ExceptionIDs exID = ExceptionIDs.ArrayTypeMismatch; IntPtr addr = array.EEType->GetAssociatedModuleAddress(); Exception e = EH.GetClasslibException(exID, addr); BinderIntrinsics.TailCall_RhpThrowEx(e); } }
static public /*internal*/ unsafe void CheckVectorElemAddr(void *pvElemType, object array) { if (array == null) { return; } Debug.Assert(array.EEType->IsArray, "second argument must be an array"); EEType *elemType = (EEType *)pvElemType; EEType *arrayElemType = array.EEType->RelatedParameterType; if (!AreTypesEquivalentInternal(elemType, arrayElemType)) { // Throw the array type mismatch exception defined by the classlib, using the input array's EEType* // to find the correct classlib. ExceptionIDs exID = ExceptionIDs.ArrayTypeMismatch; IntPtr addr = array.EEType->GetAssociatedModuleAddress(); Exception e = EH.GetClasslibException(exID, addr); BinderIntrinsics.TailCall_RhpThrowEx(e); } }
private static void DispatchEx(ref StackFrameIterator frameIter, ref ExInfo exInfo, uint startIdx) { Debug.Assert(exInfo._passNumber == 1, "expected asm throw routine to set the pass"); Exception exceptionObj = exInfo.ThrownException; // ------------------------------------------------ // // First pass // // ------------------------------------------------ UIntPtr handlingFrameSP = MaxSP; byte * pCatchHandler = null; uint catchingTryRegionIdx = MaxTryRegionIdx; bool isFirstRethrowFrame = (startIdx != MaxTryRegionIdx); bool isFirstFrame = true; UIntPtr prevFramePtr = UIntPtr.Zero; bool unwoundReversePInvoke = false; bool isValid = frameIter.Init(exInfo._pExContext); Debug.Assert(isValid, "RhThrowEx called with an unexpected context"); DebuggerNotify.BeginFirstPass(exceptionObj, frameIter.ControlPC, frameIter.SP); for (; isValid; isValid = frameIter.Next(out startIdx, out unwoundReversePInvoke)) { // For GC stackwalking, we'll happily walk across native code blocks, but for EH dispatch, we // disallow dispatching exceptions across native code. if (unwoundReversePInvoke) { break; } DebugScanCallFrame(exInfo._passNumber, frameIter.ControlPC, frameIter.SP); // A debugger can subscribe to get callbacks at a specific frame of exception dispatch // exInfo._notifyDebuggerSP can be populated by the debugger from out of process // at any time. if (exInfo._notifyDebuggerSP == frameIter.SP) { DebuggerNotify.FirstPassFrameEntered(exceptionObj, frameIter.ControlPC, frameIter.SP); } UpdateStackTrace(exceptionObj, ref exInfo, ref isFirstRethrowFrame, ref prevFramePtr, ref isFirstFrame); byte *pHandler; if (FindFirstPassHandler(exceptionObj, startIdx, ref frameIter, out catchingTryRegionIdx, out pHandler)) { handlingFrameSP = frameIter.SP; pCatchHandler = pHandler; DebugVerifyHandlingFrame(handlingFrameSP); break; } } DebuggerNotify.EndFirstPass(exceptionObj, pCatchHandler, handlingFrameSP); if (pCatchHandler == null) { UnhandledExceptionFailFastViaClasslib( RhFailFastReason.PN_UnhandledException, exceptionObj, ref exInfo); } // We FailFast above if the exception goes unhandled. Therefore, we cannot run the second pass // without a catch handler. Debug.Assert(pCatchHandler != null, "We should have a handler if we're starting the second pass"); DebuggerNotify.BeginSecondPass(); // ------------------------------------------------ // // Second pass // // ------------------------------------------------ // Due to the stackwalker logic, we cannot tolerate triggering a GC from the dispatch code once we // are in the 2nd pass. This is because the stackwalker applies a particular unwind semantic to // 'collapse' funclets which gets confused when we walk out of the dispatch code and encounter the // 'main body' without first encountering the funclet. The thunks used to invoke 2nd-pass // funclets will always toggle this mode off before invoking them. InternalCalls.RhpSetThreadDoNotTriggerGC(); exInfo._passNumber = 2; startIdx = MaxTryRegionIdx; isValid = frameIter.Init(exInfo._pExContext); for (; isValid && ((byte *)frameIter.SP <= (byte *)handlingFrameSP); isValid = frameIter.Next(out startIdx)) { Debug.Assert(isValid, "second-pass EH unwind failed unexpectedly"); DebugScanCallFrame(exInfo._passNumber, frameIter.ControlPC, frameIter.SP); if (frameIter.SP == handlingFrameSP) { // invoke only a partial second-pass here... InvokeSecondPass(ref exInfo, startIdx, catchingTryRegionIdx); break; } InvokeSecondPass(ref exInfo, startIdx); } // ------------------------------------------------ // // Call the handler and resume execution // // ------------------------------------------------ exInfo._idxCurClause = catchingTryRegionIdx; InternalCalls.RhpCallCatchFunclet( exceptionObj, pCatchHandler, frameIter.RegisterSet, ref exInfo); // currently, RhpCallCatchFunclet will resume after the catch Debug.Assert(false, "unreachable"); BinderIntrinsics.DebugBreak(); }
internal static void FailFast(RhFailFastReason reason, Exception unhandledException) { BinderIntrinsics.DebugBreak(); }