From 8da67f16fa070c68fc67e2329644a1f730e38bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Thu, 28 Mar 2024 01:40:58 +0100 Subject: [PATCH 1/5] Remove non INPLACE_RUNTIME NativeAOT paths, cleanup exceptions --- .../Runtime.Base/src/System/Array.cs | 1 + .../Runtime.Base/src/System/Exception.cs | 20 ++ .../src/System/Runtime/DispatchResolve.cs | 6 +- .../src/System/Runtime/ExceptionHandling.cs | 201 +++--------------- .../src/System/Runtime/MethodTable.Runtime.cs | 19 -- .../src/System/Runtime/RuntimeExports.cs | 30 +-- .../src/System/Runtime/TypeCast.cs | 99 ++------- .../src/System/Runtime/__Finalizer.cs | 4 +- .../Internal/Runtime/MethodTable.Runtime.cs | 5 - .../src/System.Private.CoreLib.csproj | 12 +- .../Test.CoreLib/src/System/ThrowHelper.cs | 56 +++++ .../Test.CoreLib/src/Test.CoreLib.csproj | 9 +- .../src/System/ThrowHelper.cs | 20 +- 13 files changed, 165 insertions(+), 317 deletions(-) create mode 100644 src/coreclr/nativeaot/Test.CoreLib/src/System/ThrowHelper.cs diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Array.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Array.cs index b70ddd15312ed..87eb5da1bc905 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Array.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Array.cs @@ -19,6 +19,7 @@ public partial class Array #pragma warning restore public int Length => (int)Unsafe.As(this).Length; + internal nuint NativeLength => Unsafe.As(this).Length; } // To accommodate class libraries that wish to implement generic interfaces on arrays, all class libraries diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Exception.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Exception.cs index f3851d38d7833..be11c660e8f03 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Exception.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Exception.cs @@ -86,4 +86,24 @@ internal class OutOfMemoryException : Exception { public OutOfMemoryException() { } } + + internal class EntryPointNotFoundException : Exception + { + public EntryPointNotFoundException() { } + } + + internal class AmbiguousImplementationException : Exception + { + public AmbiguousImplementationException() { } + } + + internal class DataMisalignedException : Exception + { + public DataMisalignedException() { } + } + + internal class AccessViolationException : Exception + { + public AccessViolationException() { } + } } diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/DispatchResolve.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/DispatchResolve.cs index 349415c743aa9..8cfcc9e11aa00 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/DispatchResolve.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/DispatchResolve.cs @@ -29,7 +29,7 @@ public static IntPtr FindInterfaceMethodImplementationTarget(MethodTable* pTgtTy if (FindImplSlotForCurrentType( pCur, pItfType, itfSlotNumber, fDoDefaultImplementationLookup, &implSlotNumber, ppGenericContext)) { - IntPtr targetMethod; + IntPtr targetMethod = IntPtr.Zero; if (implSlotNumber < pCur->NumVtableSlots) { // true virtual - need to get the slot from the target type in case it got overridden @@ -37,11 +37,11 @@ public static IntPtr FindInterfaceMethodImplementationTarget(MethodTable* pTgtTy } else if (implSlotNumber == SpecialDispatchMapSlot.Reabstraction) { - throw pTgtType->GetClasslibException(ExceptionIDs.EntrypointNotFound); + ThrowHelper.ThrowEntryPointNotFoundException(); } else if (implSlotNumber == SpecialDispatchMapSlot.Diamond) { - throw pTgtType->GetClasslibException(ExceptionIDs.AmbiguousImplementation); + ThrowHelper.ThrowAmbiguousImplementationException(); } else { diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs index 7ce239610a7ab..acf891bdcae73 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs @@ -291,148 +291,36 @@ private static void AppendExceptionStackFrameViaClasslib(object exception, IntPt #endif } - // 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) - { -#if NATIVEAOT - // 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.RhpGetClasslibFunctionFromCodeAddress(address, ClassLibFunctionId.GetRuntimeException); - - // Return the exception object we get from the classlib. - Exception? e = null; - try - { - e = ((delegate*)pGetRuntimeExceptionFunction)(id); - } - catch when (true) - { - // disallow all exceptions leaking out of callbacks - } -#else - Exception? e = id switch - { - ExceptionIDs.AccessViolation => new AccessViolationException(), - ExceptionIDs.Arithmetic => new ArithmeticException(), - ExceptionIDs.AmbiguousImplementation => new AmbiguousImplementationException(), - ExceptionIDs.ArrayTypeMismatch => new ArrayTypeMismatchException(), - ExceptionIDs.DataMisaligned => new DataMisalignedException(), - ExceptionIDs.DivideByZero => new DivideByZeroException(), - ExceptionIDs.EntrypointNotFound => new EntryPointNotFoundException(), - ExceptionIDs.IndexOutOfRange => new IndexOutOfRangeException(), - ExceptionIDs.InvalidCast => new InvalidCastException(), - ExceptionIDs.NullReference => new NullReferenceException(), - ExceptionIDs.OutOfMemory => new OutOfMemoryException(), - ExceptionIDs.Overflow => new OverflowException(), - _ => null - }; -#endif - // If the helper fails to yield an object, then we fail-fast. - if (e == null) - { - FailFastViaClasslib(RhFailFastReason.InternalError, null, address); - } - - return e; - } #if NATIVEAOT - // Given an ExceptionID and an MethodTable address, 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 GetClasslibExceptionFromEEType(ExceptionIDs id, MethodTable* pEEType) - { - // 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.Zero; - if (pEEType != null) - { - pGetRuntimeExceptionFunction = (IntPtr)InternalCalls.RhpGetClasslibFunctionFromEEType(pEEType, ClassLibFunctionId.GetRuntimeException); - } - - // Return the exception object we get from the classlib. - Exception? e = null; - try - { - e = ((delegate*)pGetRuntimeExceptionFunction)(id); - } - catch when (true) - { - // disallow all exceptions leaking out of callbacks - } - - // If the helper fails to yield an object, then we fail-fast. - if (e == null) - { - FailFastViaClasslib(RhFailFastReason.InternalError, null, (IntPtr)pEEType); - } - - return e; - } - +#pragma warning disable IDE0060 // RhExceptionHandling_ functions are used to throw exceptions out of our asm helpers. We tail-call from // the asm helpers to these functions, which performs the throw. The tail-call is important: it ensures that // the stack is crawlable from within these functions. [RuntimeExport("RhExceptionHandling_ThrowClasslibOverflowException")] public static void ThrowClasslibOverflowException(IntPtr address) { - // Throw the overflow exception defined by the classlib, using the return address of the asm helper - // to find the correct classlib. - - throw GetClasslibException(ExceptionIDs.Overflow, address); + ThrowHelper.ThrowOverflowException(); } [RuntimeExport("RhExceptionHandling_ThrowClasslibDivideByZeroException")] public static void ThrowClasslibDivideByZeroException(IntPtr address) { - // Throw the divide by zero exception defined by the classlib, using the return address of the asm helper - // to find the correct classlib. - - throw GetClasslibException(ExceptionIDs.DivideByZero, address); + ThrowHelper.ThrowDivideByZeroException(); } [RuntimeExport("RhExceptionHandling_FailedAllocation")] public static void FailedAllocation(MethodTable* pEEType, bool fIsOverflow) { - ExceptionIDs exID = fIsOverflow ? ExceptionIDs.Overflow : ExceptionIDs.OutOfMemory; - - // Throw the out of memory exception defined by the classlib, using the input MethodTable* - // to find the correct classlib. - - throw pEEType->GetClasslibException(exID); - } - -#if !INPLACE_RUNTIME - private static OutOfMemoryException s_theOOMException = new OutOfMemoryException(); - - // MRT exports GetRuntimeException for the few cases where we have a helper that throws an exception - // and may be called by either MRT or other classlibs and that helper needs to throw an exception. - // There are only a few cases where this happens now (the fast allocation helpers), so we limit the - // exception types that MRT will return. - [RuntimeExport("GetRuntimeException")] - public static Exception GetRuntimeException(ExceptionIDs id) - { - switch (id) + if (fIsOverflow) { - case ExceptionIDs.OutOfMemory: - // Throw a preallocated exception to avoid infinite recursion. - return s_theOOMException; - - case ExceptionIDs.Overflow: - return new OverflowException(); - - case ExceptionIDs.InvalidCast: - return new InvalidCastException(); - - default: - Debug.Assert(false, "unexpected ExceptionID"); - FallbackFailFast(RhFailFastReason.InternalError, null); - return null; + ThrowHelper.ThrowOverflowException(); + } + else + { + ThrowHelper.ThrowOutOfMemoryException(); } } -#endif +#pragma warning restore IDE0060 #endif // NATIVEAOT private enum HwExceptionCode : uint @@ -558,45 +446,44 @@ public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) #endif IntPtr faultingCodeAddress = exInfo._pExContext->IP; bool instructionFault = true; - ExceptionIDs exceptionId = default(ExceptionIDs); Exception? exceptionToThrow = null; - switch (exceptionCode) + switch ((HwExceptionCode)exceptionCode) { - case (uint)HwExceptionCode.STATUS_REDHAWK_NULL_REFERENCE: - exceptionId = ExceptionIDs.NullReference; + case HwExceptionCode.STATUS_REDHAWK_NULL_REFERENCE: + exceptionToThrow = new NullReferenceException(); break; - case (uint)HwExceptionCode.STATUS_REDHAWK_UNMANAGED_HELPER_NULL_REFERENCE: + case HwExceptionCode.STATUS_REDHAWK_UNMANAGED_HELPER_NULL_REFERENCE: // The write barrier where the actual fault happened has been unwound already. // The IP of this fault needs to be treated as return address, not as IP of // faulting instruction. instructionFault = false; - exceptionId = ExceptionIDs.NullReference; + exceptionToThrow = new NullReferenceException(); break; #if NATIVEAOT - case (uint)HwExceptionCode.STATUS_REDHAWK_THREAD_ABORT: + case HwExceptionCode.STATUS_REDHAWK_THREAD_ABORT: exceptionToThrow = InternalCalls.RhpGetThreadAbortException(); break; #endif - case (uint)HwExceptionCode.STATUS_DATATYPE_MISALIGNMENT: - exceptionId = ExceptionIDs.DataMisaligned; + case HwExceptionCode.STATUS_DATATYPE_MISALIGNMENT: + exceptionToThrow = new DataMisalignedException(); 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; + case HwExceptionCode.STATUS_ACCESS_VIOLATION: + exceptionToThrow = new AccessViolationException(); break; - case (uint)HwExceptionCode.STATUS_INTEGER_DIVIDE_BY_ZERO: - exceptionId = ExceptionIDs.DivideByZero; + case HwExceptionCode.STATUS_INTEGER_DIVIDE_BY_ZERO: + exceptionToThrow = new DivideByZeroException(); break; - case (uint)HwExceptionCode.STATUS_INTEGER_OVERFLOW: - exceptionId = ExceptionIDs.Overflow; + case HwExceptionCode.STATUS_INTEGER_OVERFLOW: + exceptionToThrow = new OverflowException(); break; default: @@ -607,11 +494,6 @@ public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) break; } - if (exceptionId != default(ExceptionIDs)) - { - exceptionToThrow = GetClasslibException(exceptionId, faultingCodeAddress); - } - exInfo.Init(exceptionToThrow!, instructionFault); DispatchEx(ref exInfo._frameIter, ref exInfo); FallbackFailFast(RhFailFastReason.InternalError, null); @@ -631,11 +513,7 @@ public static void RhThrowEx(object exceptionObj, ref ExInfo exInfo) InternalCalls.RhpValidateExInfoStack(); #endif // Transform attempted throws of null to a throw of NullReferenceException. - if (exceptionObj == null) - { - IntPtr faultingCodeAddress = exInfo._pExContext->IP; - exceptionObj = GetClasslibException(ExceptionIDs.NullReference, faultingCodeAddress); - } + exceptionObj ??= new NullReferenceException(); exInfo.Init(exceptionObj); DispatchEx(ref exInfo._frameIter, ref exInfo); @@ -1078,38 +956,9 @@ private static bool FindFirstPassHandler(object exception, uint idxStart, return false; } -#if DEBUG && !INPLACE_RUNTIME && NATIVEAOT - private static MethodTable* s_pLowLevelObjectType; - private static void AssertNotRuntimeObject(MethodTable* pClauseType) - { - // - // The C# try { } catch { } clause expands into a typed catch of System.Object. - // Since runtime has its own definition of System.Object, try { } catch { } might not do what - // was intended (catch all exceptions). - // - // This assertion is making sure we don't use try { } catch { } within the runtime. - // The runtime codebase should either use try { } catch (Exception) { } for exception types - // from the runtime or a try { } catch when (true) { } to catch all exceptions. - // - - if (s_pLowLevelObjectType == null) - { - // Allocating might fail, but since this is just a debug assert, it's probably fine. - s_pLowLevelObjectType = new System.Object().MethodTable; - } - - Debug.Assert(!pClauseType->IsEquivalentTo(s_pLowLevelObjectType)); - } -#endif // DEBUG && !INPLACE_RUNTIME && NATIVEAOT - - private static bool ShouldTypedClauseCatchThisException(object exception, MethodTable* pClauseType, bool tryUnwrapException) { #if NATIVEAOT -#if DEBUG && !INPLACE_RUNTIME - AssertNotRuntimeObject(pClauseType); -#endif - return TypeCast.IsInstanceOfException(pClauseType, exception); #else if (tryUnwrapException && exception is RuntimeWrappedException ex) diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/MethodTable.Runtime.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/MethodTable.Runtime.cs index 1c786946c82bf..8bd44f7fa0121 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/MethodTable.Runtime.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/MethodTable.Runtime.cs @@ -11,25 +11,6 @@ namespace Internal.Runtime // Extensions to MethodTable that are specific to the use in Runtime.Base. internal unsafe partial struct MethodTable { -#if !INPLACE_RUNTIME - internal MethodTable* GetArrayEEType() - { - MethodTable* pThis = (MethodTable*)Unsafe.Pointer(ref this); - void* pGetArrayEEType = InternalCalls.RhpGetClasslibFunctionFromEEType(pThis, ClassLibFunctionId.GetSystemArrayEEType); - return ((delegate* )pGetArrayEEType)(); - } - - internal Exception GetClasslibException(ExceptionIDs id) - { - if (IsParameterizedType) - { - return RelatedParameterType->GetClasslibException(id); - } - - return EH.GetClasslibExceptionFromEEType(id, (MethodTable*)Unsafe.AsPointer(ref this)); - } -#endif - internal IntPtr GetClasslibFunction(ClassLibFunctionId id) { return (IntPtr)InternalCalls.RhpGetClasslibFunctionFromEEType((MethodTable*)Unsafe.AsPointer(ref this), id); diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs index 378fabf56836f..9c642bb521323 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs @@ -166,7 +166,7 @@ public static unsafe void RhUnboxAny(object? o, ref byte data, MethodTable* pUnb { if (pUnboxToEEType->IsValueType) { - bool isValid = false; + bool isValid; if (pUnboxToEEType->IsNullable) { @@ -174,17 +174,16 @@ public static unsafe void RhUnboxAny(object? o, ref byte data, MethodTable* pUnb } else { - isValid = (o != null) && UnboxAnyTypeCompare(o.GetMethodTable(), pUnboxToEEType); + if (o == null) + { + ThrowHelper.ThrowNullReferenceException(); + } + isValid = UnboxAnyTypeCompare(o.GetMethodTable(), pUnboxToEEType); } if (!isValid) { - // Throw the invalid cast exception defined by the classlib, using the input unbox MethodTable* - // to find the correct classlib. - - ExceptionIDs exID = o == null ? ExceptionIDs.NullReference : ExceptionIDs.InvalidCast; - - throw pUnboxToEEType->GetClasslibException(exID); + ThrowHelper.ThrowInvalidCastException(); } RhUnbox(o, ref data, pUnboxToEEType); @@ -193,7 +192,7 @@ public static unsafe void RhUnboxAny(object? o, ref byte data, MethodTable* pUnb { if (o != null && (TypeCast.IsInstanceOfAny(pUnboxToEEType, o) == null)) { - throw pUnboxToEEType->GetClasslibException(ExceptionIDs.InvalidCast); + ThrowHelper.ThrowInvalidCastException(); } Unsafe.As(ref data) = o; @@ -206,11 +205,16 @@ public static unsafe void RhUnboxAny(object? o, ref byte data, MethodTable* pUnb [RuntimeExport("RhUnbox2")] public static unsafe ref byte RhUnbox2(MethodTable* pUnboxToEEType, object obj) { - if ((obj == null) || !UnboxAnyTypeCompare(obj.GetMethodTable(), pUnboxToEEType)) + if (obj == null) { - ExceptionIDs exID = obj == null ? ExceptionIDs.NullReference : ExceptionIDs.InvalidCast; - throw pUnboxToEEType->GetClasslibException(exID); + ThrowHelper.ThrowNullReferenceException(); } + + if (!UnboxAnyTypeCompare(obj.GetMethodTable(), pUnboxToEEType)) + { + ThrowHelper.ThrowInvalidCastException(); + } + return ref obj.GetRawData(); } @@ -219,7 +223,7 @@ public static unsafe void RhUnboxNullable(ref byte data, MethodTable* pUnboxToEE { if (obj != null && obj.GetMethodTable() != pUnboxToEEType->NullableType) { - throw pUnboxToEEType->GetClasslibException(ExceptionIDs.InvalidCast); + ThrowHelper.ThrowInvalidCastException(); } RhUnbox(obj, ref data, pUnboxToEEType); } diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs index 0161e8c47c150..be5d87491d882 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs @@ -382,15 +382,13 @@ private static unsafe object CheckCastInterface_Helper(MethodTable* pTargetType, { // If object type implements IDynamicInterfaceCastable then there's one more way to check whether it implements // the interface. - if (obj.GetMethodTable()->IsIDynamicInterfaceCastable - && IsInstanceOfInterfaceViaIDynamicInterfaceCastable(pTargetType, obj, throwing: true)) + if (!obj.GetMethodTable()->IsIDynamicInterfaceCastable + || !IsInstanceOfInterfaceViaIDynamicInterfaceCastable(pTargetType, obj, throwing: true)) { - return obj; + ThrowHelper.ThrowInvalidCastException(); } - // Throw the invalid cast exception defined by the classlib, using the input MethodTable* to find the - // correct classlib. - return ThrowInvalidCastException(pTargetType); + return obj; } [RuntimeExport("RhTypeCast_CheckCastClass")] @@ -432,7 +430,7 @@ private static unsafe object CheckCastClassSpecial(MethodTable* pTargetType, obj goto done; // They don't cast to any other class - goto fail; + ThrowHelper.ThrowInvalidCastException(); } for (; ; ) @@ -466,13 +464,10 @@ private static unsafe object CheckCastClassSpecial(MethodTable* pTargetType, obj break; } - goto fail; + ThrowHelper.ThrowInvalidCastException(); done: return obj; - - fail: - return ThrowInvalidCastException(pTargetType); } private static unsafe bool IsInstanceOfInterfaceViaIDynamicInterfaceCastable(MethodTable* pTargetType, object obj, bool throwing) @@ -738,24 +733,7 @@ public static unsafe void CheckArrayStore(object array, object obj) if (obj.GetMethodTable()->IsIDynamicInterfaceCastable && IsInstanceOfInterfaceViaIDynamicInterfaceCastable(arrayElemType, obj, throwing: false)) return; - // Throw the array type mismatch exception defined by the classlib, using the input array's MethodTable* - // to find the correct classlib. - - throw array.GetMethodTable()->GetClasslibException(ExceptionIDs.ArrayTypeMismatch); - } - - private static unsafe void ThrowIndexOutOfRangeException(object?[] array) - { - // Throw the index out of range exception defined by the classlib, using the input array's MethodTable* - // to find the correct classlib. - throw array.GetMethodTable()->GetClasslibException(ExceptionIDs.IndexOutOfRange); - } - - private static unsafe void ThrowArrayMismatchException(object?[] array) - { - // Throw the array type mismatch exception defined by the classlib, using the input array's MethodTable* - // to find the correct classlib. - throw array.GetMethodTable()->GetClasslibException(ExceptionIDs.ArrayTypeMismatch); + ThrowHelper.ThrowArrayTypeMismatchException(); } // @@ -767,29 +745,16 @@ private static unsafe void ThrowArrayMismatchException(object?[] array) { Debug.Assert(array is null || array.GetMethodTable()->IsArray, "first argument must be an array"); -#if INPLACE_RUNTIME // This will throw NullReferenceException if obj is null. - if ((nuint)index >= (uint)array.Length) - ThrowIndexOutOfRangeException(array); + if ((nuint)index >= array.NativeLength) + ThrowHelper.ThrowIndexOutOfRangeException(); Debug.Assert(index >= 0); ref object? element = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), index); -#else - if (array is null) - { - throw elementType->GetClasslibException(ExceptionIDs.NullReference); - } - if ((nuint)index >= (uint)array.Length) - { - throw elementType->GetClasslibException(ExceptionIDs.IndexOutOfRange); - } - ref object rawData = ref Unsafe.As(ref Unsafe.As(array).Data); - ref object element = ref Unsafe.Add(ref rawData, index); -#endif MethodTable* arrayElemType = array.GetMethodTable()->RelatedParameterType; if (elementType != arrayElemType) - ThrowArrayMismatchException(array); + ThrowHelper.ThrowArrayTypeMismatchException(); return ref element; } @@ -800,27 +765,12 @@ public static unsafe void StelemRef(object?[] array, nint index, object? obj) // This is supported only on arrays Debug.Assert(array is null || array.GetMethodTable()->IsArray, "first argument must be an array"); -#if INPLACE_RUNTIME // This will throw NullReferenceException if obj is null. - if ((nuint)index >= (uint)array.Length) - ThrowIndexOutOfRangeException(array); + if ((nuint)index >= array.NativeLength) + ThrowHelper.ThrowIndexOutOfRangeException(); Debug.Assert(index >= 0); ref object? element = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), index); -#else - if (array is null) - { - // TODO: If both array and obj are null, we're likely going to throw Redhawk's NullReferenceException. - // This should blame the caller. - throw obj.GetMethodTable()->GetClasslibException(ExceptionIDs.NullReference); - } - if ((uint)index >= (uint)array.Length) - { - throw array.GetMethodTable()->GetClasslibException(ExceptionIDs.IndexOutOfRange); - } - ref object rawData = ref Unsafe.As(ref Unsafe.As(array).Data); - ref object element = ref Unsafe.Add(ref rawData, index); -#endif MethodTable* elementType = array.GetMethodTable()->RelatedParameterType; @@ -839,11 +789,8 @@ public static unsafe void StelemRef(object?[] array, nint index, object? obj) return; notExactMatch: -#if INPLACE_RUNTIME - // This optimization only makes sense for inplace runtime where there's only one System.Object. if (array.GetMethodTable() == MethodTable.Of()) goto doWrite; -#endif StelemRef_Helper(ref element, elementType, obj); } @@ -866,9 +813,7 @@ private static unsafe void StelemRef_Helper_NoCacheLookup(ref object? element, M object? castedObj = IsInstanceOfAny_NoCacheLookup(elementType, obj); if (castedObj == null) { - // Throw the array type mismatch exception defined by the classlib, using the input array's - // MethodTable* to find the correct classlib. - throw elementType->GetClasslibException(ExceptionIDs.ArrayTypeMismatch); + ThrowHelper.ThrowArrayTypeMismatchException(); } InternalCalls.RhpAssignRef(ref element, obj); @@ -918,10 +863,7 @@ private static unsafe object CheckCastArray(MethodTable* pTargetEEType, object o if (result == null) { - // Throw the invalid cast exception defined by the classlib, using the input MethodTable* - // to find the correct classlib. - - return ThrowInvalidCastException(pTargetEEType); + ThrowHelper.ThrowInvalidCastException(); } return result; @@ -945,7 +887,7 @@ private static unsafe object CheckCastVariantType(MethodTable* pTargetType, obje && (!obj.GetMethodTable()->IsIDynamicInterfaceCastable || !IsInstanceOfInterfaceViaIDynamicInterfaceCastable(pTargetType, obj, throwing: true))) { - return ThrowInvalidCastException(pTargetType); + ThrowHelper.ThrowInvalidCastException(); } return obj; @@ -967,13 +909,6 @@ private static unsafe EETypeElementType GetNormalizedIntegralArrayElementType(Me return elementType; } - // Would not be inlined, but still need to mark NoInlining so that it doesn't throw off tail calls - [MethodImpl(MethodImplOptions.NoInlining)] - private static unsafe object ThrowInvalidCastException(MethodTable* pMT) - { - throw pMT->GetClasslibException(ExceptionIDs.InvalidCast); - } - internal unsafe struct EETypePairList { private MethodTable* _eetype1; @@ -1284,9 +1219,7 @@ private static unsafe object CheckCastAny_NoCacheLookup(MethodTable* pTargetType } else if (pTargetType->IsParameterizedType || pTargetType->IsFunctionPointer) { - // We handled arrays above so this is for pointers and byrefs only. - // Nothing can be a boxed instance of these. - return ThrowInvalidCastException(pTargetType); + ThrowHelper.ThrowInvalidCastException(); } else { diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/__Finalizer.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/__Finalizer.cs index a55b7fc040d25..6f30686fb5fb4 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/__Finalizer.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/__Finalizer.cs @@ -19,9 +19,7 @@ internal static class __Finalizer [UnmanagedCallersOnly(EntryPoint = "ProcessFinalizers")] public static void ProcessFinalizers() { -#if INPLACE_RUNTIME - System.Runtime.FinalizerInitRunner.DoInitialize(); -#endif + FinalizerInitRunner.DoInitialize(); while (true) { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/MethodTable.Runtime.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/MethodTable.Runtime.cs index 899ac448d5f9d..2b37d6f9206b8 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/MethodTable.Runtime.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/MethodTable.Runtime.cs @@ -16,11 +16,6 @@ internal unsafe partial struct MethodTable { return MethodTable.Of(); } - - internal Exception GetClasslibException(ExceptionIDs id) - { - return RuntimeExceptionHelpers.GetRuntimeException(id); - } #pragma warning restore CA1822 internal static bool AreSameType(MethodTable* mt1, MethodTable* mt2) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 70928c997a508..f8e244f7f1b10 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -205,7 +205,7 @@ - + @@ -281,7 +281,7 @@ Interop\Windows\Ole32\Interop.CoGetContextToken.cs - + Interop\Windows\OleAut32\Interop.VariantClear.cs @@ -507,10 +507,6 @@ - true - - - INPLACE_RUNTIME;$(DefineConstants) FEATURE_64BIT_ALIGNMENT;$(DefineConstants) FEATURE_64BIT_ALIGNMENT;$(DefineConstants) FEATURE_64BIT_ALIGNMENT;$(DefineConstants) @@ -518,7 +514,7 @@ $(ArtifactsObjDir)\coreclr\$(TargetOS).$(TargetArchitecture).$(CoreCLRConfiguration) $(IntermediatesDir)\ide - + Runtime.Base\src\System\Runtime\CachedInterfaceDispatch.cs @@ -556,7 +552,7 @@ Common\TransitionBlock.cs - + diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/System/ThrowHelper.cs b/src/coreclr/nativeaot/Test.CoreLib/src/System/ThrowHelper.cs new file mode 100644 index 0000000000000..4dcf0c29a8ee5 --- /dev/null +++ b/src/coreclr/nativeaot/Test.CoreLib/src/System/ThrowHelper.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; + +namespace System +{ + [StackTraceHidden] + internal static class ThrowHelper + { + internal static void ThrowEntryPointNotFoundException() + { + throw new EntryPointNotFoundException(); + } + + internal static void ThrowAmbiguousImplementationException() + { + throw new AmbiguousImplementationException(); + } + + internal static void ThrowOverflowException() + { + throw new OverflowException(); + } + + internal static void ThrowDivideByZeroException() + { + throw new DivideByZeroException(); + } + + internal static void ThrowOutOfMemoryException() + { + throw new OutOfMemoryException(); + } + + internal static void ThrowNullReferenceException() + { + throw new NullReferenceException(); + } + + internal static void ThrowInvalidCastException() + { + throw new InvalidCastException(); + } + + internal static void ThrowArrayTypeMismatchException() + { + throw new ArrayTypeMismatchException(); + } + + internal static void ThrowIndexOutOfRangeException() + { + throw new IndexOutOfRangeException(); + } + } +} diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj b/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj index 498dc441b9763..1ef37ec04bca5 100644 --- a/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj +++ b/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj @@ -18,10 +18,6 @@ - true - - - INPLACE_RUNTIME;$(DefineConstants) FEATURE_64BIT_ALIGNMENT;$(DefineConstants) FEATURE_64BIT_ALIGNMENT;$(DefineConstants) @@ -31,7 +27,7 @@ $([MSBuild]::NormalizeDirectory('$(LibrariesProjectRoot)', 'Common', 'src')) - + Runtime.Base\src\System\Runtime\CachedInterfaceDispatch.cs @@ -72,7 +68,7 @@ Common\Interop\Windows\Interop.BOOL.cs - + @@ -233,6 +229,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs index eb9b5b7eb0261..b78e0ea774a2f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs @@ -65,6 +65,18 @@ internal static void ThrowAccessViolationException() throw new AccessViolationException(); } + [DoesNotReturn] + internal static void ThrowAmbiguousImplementationException() + { + throw new AmbiguousImplementationException(); + } + + [DoesNotReturn] + internal static void ThrowEntryPointNotFoundException() + { + throw new EntryPointNotFoundException(); + } + [DoesNotReturn] internal static void ThrowArrayTypeMismatchException() { @@ -77,6 +89,12 @@ internal static void ThrowArrayTypeMismatchException_CantAssignType() throw new ArrayTypeMismatchException(SR.ArrayTypeMismatch_CantAssignType); } + [DoesNotReturn] + internal static void ThrowInvalidCastException() + { + throw new InvalidCastException(); + } + [DoesNotReturn] internal static void ThrowInvalidCastException_DownCastArrayElement() { @@ -419,7 +437,7 @@ internal static void ThrowInvalidOperationException(ExceptionResource resource, [DoesNotReturn] internal static void ThrowNullReferenceException() { - throw new NullReferenceException(SR.Arg_NullArgumentNullRef); + throw new NullReferenceException(); } [DoesNotReturn] From da61990fadc2b7d5621f15d2e0eee69b7e982b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Fri, 29 Mar 2024 03:59:41 +0100 Subject: [PATCH 2/5] Review changes --- .../src/System/Runtime/ExceptionHandling.cs | 79 ++++++++++++++----- .../src/System/Runtime/RuntimeExports.cs | 9 --- .../Runtime/InitializeFinalizerThread.cs | 1 - 3 files changed, 59 insertions(+), 30 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs index acf891bdcae73..b9510a79272a0 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs @@ -291,25 +291,59 @@ private static void AppendExceptionStackFrameViaClasslib(object exception, IntPt #endif } -#if NATIVEAOT -#pragma warning disable IDE0060 - // RhExceptionHandling_ functions are used to throw exceptions out of our asm helpers. We tail-call from - // the asm helpers to these functions, which performs the throw. The tail-call is important: it ensures that - // the stack is crawlable from within these functions. - [RuntimeExport("RhExceptionHandling_ThrowClasslibOverflowException")] - public static void ThrowClasslibOverflowException(IntPtr address) + // 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) { - ThrowHelper.ThrowOverflowException(); - } +#if NATIVEAOT + // 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.RhpGetClasslibFunctionFromCodeAddress(address, ClassLibFunctionId.GetRuntimeException); - [RuntimeExport("RhExceptionHandling_ThrowClasslibDivideByZeroException")] - public static void ThrowClasslibDivideByZeroException(IntPtr address) - { - ThrowHelper.ThrowDivideByZeroException(); + // Return the exception object we get from the classlib. + Exception? e = null; + try + { + e = ((delegate*)pGetRuntimeExceptionFunction)(id); + } + catch when (true) + { + // disallow all exceptions leaking out of callbacks + } +#else + Exception? e = id switch + { + ExceptionIDs.AccessViolation => new AccessViolationException(), + ExceptionIDs.Arithmetic => new ArithmeticException(), + ExceptionIDs.AmbiguousImplementation => new AmbiguousImplementationException(), + ExceptionIDs.ArrayTypeMismatch => new ArrayTypeMismatchException(), + ExceptionIDs.DataMisaligned => new DataMisalignedException(), + ExceptionIDs.DivideByZero => new DivideByZeroException(), + ExceptionIDs.EntrypointNotFound => new EntryPointNotFoundException(), + ExceptionIDs.IndexOutOfRange => new IndexOutOfRangeException(), + ExceptionIDs.InvalidCast => new InvalidCastException(), + ExceptionIDs.NullReference => new NullReferenceException(), + ExceptionIDs.OutOfMemory => new OutOfMemoryException(), + ExceptionIDs.Overflow => new OverflowException(), + _ => null + }; +#endif + // If the helper fails to yield an object, then we fail-fast. + if (e == null) + { + FailFastViaClasslib(RhFailFastReason.InternalError, null, address); + } + + return e; } +#if NATIVEAOT [RuntimeExport("RhExceptionHandling_FailedAllocation")] +#pragma warning disable IDE0060 public static void FailedAllocation(MethodTable* pEEType, bool fIsOverflow) +#pragma warning restore IDE0060 { if (fIsOverflow) { @@ -320,7 +354,6 @@ public static void FailedAllocation(MethodTable* pEEType, bool fIsOverflow) ThrowHelper.ThrowOutOfMemoryException(); } } -#pragma warning restore IDE0060 #endif // NATIVEAOT private enum HwExceptionCode : uint @@ -446,12 +479,13 @@ public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) #endif IntPtr faultingCodeAddress = exInfo._pExContext->IP; bool instructionFault = true; + ExceptionIDs exceptionId = 0; Exception? exceptionToThrow = null; switch ((HwExceptionCode)exceptionCode) { case HwExceptionCode.STATUS_REDHAWK_NULL_REFERENCE: - exceptionToThrow = new NullReferenceException(); + exceptionId = ExceptionIDs.NullReference; break; case HwExceptionCode.STATUS_REDHAWK_UNMANAGED_HELPER_NULL_REFERENCE: @@ -459,7 +493,7 @@ public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) // The IP of this fault needs to be treated as return address, not as IP of // faulting instruction. instructionFault = false; - exceptionToThrow = new NullReferenceException(); + exceptionId = ExceptionIDs.NullReference; break; #if NATIVEAOT @@ -469,21 +503,21 @@ public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) #endif case HwExceptionCode.STATUS_DATATYPE_MISALIGNMENT: - exceptionToThrow = new DataMisalignedException(); + 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 HwExceptionCode.STATUS_ACCESS_VIOLATION: - exceptionToThrow = new AccessViolationException(); + exceptionId = ExceptionIDs.AccessViolation; break; case HwExceptionCode.STATUS_INTEGER_DIVIDE_BY_ZERO: - exceptionToThrow = new DivideByZeroException(); + exceptionId = ExceptionIDs.DivideByZero; break; case HwExceptionCode.STATUS_INTEGER_OVERFLOW: - exceptionToThrow = new OverflowException(); + exceptionId = ExceptionIDs.Overflow; break; default: @@ -494,6 +528,11 @@ public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) break; } + if (exceptionId != 0) + { + exceptionToThrow = GetClasslibException(exceptionId, faultingCodeAddress); + } + exInfo.Init(exceptionToThrow!, instructionFault); DispatchEx(ref exInfo._frameIter, ref exInfo); FallbackFailFast(RhFailFastReason.InternalError, null); diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs index 9c642bb521323..cbdfdca41b809 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs @@ -174,10 +174,6 @@ public static unsafe void RhUnboxAny(object? o, ref byte data, MethodTable* pUnb } else { - if (o == null) - { - ThrowHelper.ThrowNullReferenceException(); - } isValid = UnboxAnyTypeCompare(o.GetMethodTable(), pUnboxToEEType); } @@ -205,11 +201,6 @@ public static unsafe void RhUnboxAny(object? o, ref byte data, MethodTable* pUnb [RuntimeExport("RhUnbox2")] public static unsafe ref byte RhUnbox2(MethodTable* pUnboxToEEType, object obj) { - if (obj == null) - { - ThrowHelper.ThrowNullReferenceException(); - } - if (!UnboxAnyTypeCompare(obj.GetMethodTable(), pUnboxToEEType)) { ThrowHelper.ThrowInvalidCastException(); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InitializeFinalizerThread.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InitializeFinalizerThread.cs index d0021229b7522..ca0beaf62dcaf 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InitializeFinalizerThread.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InitializeFinalizerThread.cs @@ -9,7 +9,6 @@ internal static class FinalizerInitRunner { // Here, we are subscribing to a callback from the runtime. This callback is made from the finalizer // thread before any objects are finalized. - [RuntimeExport("InitializeFinalizerThread")] public static void DoInitialize() { // Make sure that the finalizer thread is CoInitialized before any objects are finalized. If this From 10ab9780eef2bd8727b5324d2fde4b0228a5492b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Sat, 30 Mar 2024 03:16:22 +0100 Subject: [PATCH 3/5] Review --- .../src/System/Runtime/ExceptionHandling.cs | 16 +++++++--------- .../src/System/Runtime/InternalCalls.cs | 2 +- .../src/System/Runtime/RuntimeExports.cs | 2 ++ .../Runtime.Base/src/System/Runtime/TypeCast.cs | 7 +++++-- .../src/Resources/Strings.resx | 3 --- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs index b9510a79272a0..2c578cc05f486 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs @@ -345,14 +345,8 @@ internal static Exception GetClasslibException(ExceptionIDs id, IntPtr address) public static void FailedAllocation(MethodTable* pEEType, bool fIsOverflow) #pragma warning restore IDE0060 { - if (fIsOverflow) - { - ThrowHelper.ThrowOverflowException(); - } - else - { - ThrowHelper.ThrowOutOfMemoryException(); - } + ExceptionIDs exID = fIsOverflow ? ExceptionIDs.Overflow : ExceptionIDs.OutOfMemory; + throw RuntimeExceptionHelpers.GetRuntimeException(exID)!; } #endif // NATIVEAOT @@ -552,7 +546,11 @@ public static void RhThrowEx(object exceptionObj, ref ExInfo exInfo) InternalCalls.RhpValidateExInfoStack(); #endif // Transform attempted throws of null to a throw of NullReferenceException. - exceptionObj ??= new NullReferenceException(); + if (exceptionObj == null) + { + IntPtr faultingCodeAddress = exInfo._pExContext->IP; + exceptionObj = GetClasslibException(ExceptionIDs.NullReference, faultingCodeAddress); + } exInfo.Init(exceptionObj); DispatchEx(ref exInfo._frameIter, ref exInfo); diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs index 7ea73ba7c2c38..34bc063acd04f 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs @@ -41,7 +41,7 @@ internal enum ClassLibFunctionId // UnhandledExceptionHandler = 2, // unused AppendExceptionStackFrame = 3, // unused = 4, - GetSystemArrayEEType = 5, + // GetSystemArrayEEType = 5, // unused OnFirstChance = 6, OnUnhandledException = 7, IDynamicCastableIsInterfaceImplemented = 8, diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs index cbdfdca41b809..58d88ae4e0d74 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/RuntimeExports.cs @@ -174,6 +174,7 @@ public static unsafe void RhUnboxAny(object? o, ref byte data, MethodTable* pUnb } else { + // This will throw NullReferenceException if obj is null. isValid = UnboxAnyTypeCompare(o.GetMethodTable(), pUnboxToEEType); } @@ -201,6 +202,7 @@ public static unsafe void RhUnboxAny(object? o, ref byte data, MethodTable* pUnb [RuntimeExport("RhUnbox2")] public static unsafe ref byte RhUnbox2(MethodTable* pUnboxToEEType, object obj) { + // This will throw NullReferenceException if obj is null. if (!UnboxAnyTypeCompare(obj.GetMethodTable(), pUnboxToEEType)) { ThrowHelper.ThrowInvalidCastException(); diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs index be5d87491d882..b56f2a771eff8 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs @@ -382,6 +382,7 @@ private static unsafe object CheckCastInterface_Helper(MethodTable* pTargetType, { // If object type implements IDynamicInterfaceCastable then there's one more way to check whether it implements // the interface. + // This will throw NullReferenceException if obj is null. if (!obj.GetMethodTable()->IsIDynamicInterfaceCastable || !IsInstanceOfInterfaceViaIDynamicInterfaceCastable(pTargetType, obj, throwing: true)) { @@ -746,7 +747,7 @@ public static unsafe void CheckArrayStore(object array, object obj) Debug.Assert(array is null || array.GetMethodTable()->IsArray, "first argument must be an array"); // This will throw NullReferenceException if obj is null. - if ((nuint)index >= array.NativeLength) + if ((nuint)index >= (uint)array.Length) ThrowHelper.ThrowIndexOutOfRangeException(); Debug.Assert(index >= 0); @@ -766,7 +767,7 @@ public static unsafe void StelemRef(object?[] array, nint index, object? obj) Debug.Assert(array is null || array.GetMethodTable()->IsArray, "first argument must be an array"); // This will throw NullReferenceException if obj is null. - if ((nuint)index >= array.NativeLength) + if ((nuint)index >= (uint)array.Length) ThrowHelper.ThrowIndexOutOfRangeException(); Debug.Assert(index >= 0); @@ -871,6 +872,7 @@ private static unsafe object CheckCastArray(MethodTable* pTargetEEType, object o private static unsafe object IsInstanceOfVariantType(MethodTable* pTargetType, object obj) { + // This will throw NullReferenceException if obj is null. if (!AreTypesAssignableInternal(obj.GetMethodTable(), pTargetType, AssignmentVariation.BoxedSource, null) && (!obj.GetMethodTable()->IsIDynamicInterfaceCastable || !IsInstanceOfInterfaceViaIDynamicInterfaceCastable(pTargetType, obj, throwing: false))) @@ -883,6 +885,7 @@ private static unsafe object IsInstanceOfVariantType(MethodTable* pTargetType, o private static unsafe object CheckCastVariantType(MethodTable* pTargetType, object obj) { + // This will throw NullReferenceException if obj is null. if (!AreTypesAssignableInternal(obj.GetMethodTable(), pTargetType, AssignmentVariation.BoxedSource, null) && (!obj.GetMethodTable()->IsIDynamicInterfaceCastable || !IsInstanceOfInterfaceViaIDynamicInterfaceCastable(pTargetType, obj, throwing: true))) diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index bbc4b27c51dde..d6762e2f4eea6 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -3734,9 +3734,6 @@ Number of elements in source vector is greater than the destination array - - The method was called with a null array argument. - AggressiveGC requires setting the generation parameter to MaxGeneration From 9c9ce9090b4ba9ee0f75ef374c2fb9539d0a5723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Mon, 1 Apr 2024 18:03:56 +0200 Subject: [PATCH 4/5] Cleanup --- src/coreclr/nativeaot/Bootstrap/main.cpp | 3 --- .../Runtime.Base/src/System/Array.cs | 1 - .../Runtime.Base/src/System/Exception.cs | 10 --------- .../src/System/Runtime/InternalCalls.cs | 21 ++++++++----------- src/coreclr/nativeaot/Runtime/ICodeManager.h | 21 ++++++++----------- .../src/System/Array.NativeAot.cs | 8 ------- .../Test.CoreLib/src/System/Array.cs | 20 ------------------ .../Test.CoreLib/src/Test.CoreLib.csproj | 1 - 8 files changed, 18 insertions(+), 67 deletions(-) delete mode 100644 src/coreclr/nativeaot/Test.CoreLib/src/System/Array.cs diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index 16ffe8f9dbcb0..94afc2dfff8e3 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -138,10 +138,7 @@ typedef void (CDECL *pfn)(); static const pfn c_classlibFunctions[] = { &MANAGED_RUNTIME_EXPORT_NAME(GetRuntimeException), &MANAGED_RUNTIME_EXPORT_NAME(RuntimeFailFast), - nullptr, // &UnhandledExceptionHandler, &MANAGED_RUNTIME_EXPORT_NAME(AppendExceptionStackFrame), - nullptr, // &CheckStaticClassConstruction, - &MANAGED_RUNTIME_EXPORT_NAME(GetSystemArrayEEType), &MANAGED_RUNTIME_EXPORT_NAME(OnFirstChanceException), &MANAGED_RUNTIME_EXPORT_NAME(OnUnhandledException), &MANAGED_RUNTIME_EXPORT_NAME(IDynamicCastableIsInterfaceImplemented), diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Array.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Array.cs index 87eb5da1bc905..b70ddd15312ed 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Array.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Array.cs @@ -19,7 +19,6 @@ public partial class Array #pragma warning restore public int Length => (int)Unsafe.As(this).Length; - internal nuint NativeLength => Unsafe.As(this).Length; } // To accommodate class libraries that wish to implement generic interfaces on arrays, all class libraries diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Exception.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Exception.cs index be11c660e8f03..5a94b19b0049b 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Exception.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Exception.cs @@ -96,14 +96,4 @@ internal class AmbiguousImplementationException : Exception { public AmbiguousImplementationException() { } } - - internal class DataMisalignedException : Exception - { - public DataMisalignedException() { } - } - - internal class AccessViolationException : Exception - { - public AccessViolationException() { } - } } diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs index 34bc063acd04f..0efef08af6a31 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs @@ -38,18 +38,15 @@ internal enum ClassLibFunctionId { GetRuntimeException = 0, FailFast = 1, - // UnhandledExceptionHandler = 2, // unused - AppendExceptionStackFrame = 3, - // unused = 4, - // GetSystemArrayEEType = 5, // unused - OnFirstChance = 6, - OnUnhandledException = 7, - IDynamicCastableIsInterfaceImplemented = 8, - IDynamicCastableGetInterfaceImplementation = 9, - ObjectiveCMarshalTryGetTaggedMemory = 10, - ObjectiveCMarshalGetIsTrackedReferenceCallback = 11, - ObjectiveCMarshalGetOnEnteredFinalizerQueueCallback = 12, - ObjectiveCMarshalGetUnhandledExceptionPropagationHandler = 13, + AppendExceptionStackFrame = 2, + OnFirstChance = 3, + OnUnhandledException = 4, + IDynamicCastableIsInterfaceImplemented = 5, + IDynamicCastableGetInterfaceImplementation = 6, + ObjectiveCMarshalTryGetTaggedMemory = 7, + ObjectiveCMarshalGetIsTrackedReferenceCallback = 8, + ObjectiveCMarshalGetOnEnteredFinalizerQueueCallback = 9, + ObjectiveCMarshalGetUnhandledExceptionPropagationHandler = 10, } internal static class InternalCalls diff --git a/src/coreclr/nativeaot/Runtime/ICodeManager.h b/src/coreclr/nativeaot/Runtime/ICodeManager.h index dfc6e9efa915a..76de0a8e88eda 100644 --- a/src/coreclr/nativeaot/Runtime/ICodeManager.h +++ b/src/coreclr/nativeaot/Runtime/ICodeManager.h @@ -186,18 +186,15 @@ enum class ClasslibFunctionId { GetRuntimeException = 0, FailFast = 1, - UnhandledExceptionHandler = 2, - AppendExceptionStackFrame = 3, - // unused = 4, - GetSystemArrayEEType = 5, - OnFirstChanceException = 6, - OnUnhandledException = 7, - IDynamicCastableIsInterfaceImplemented = 8, - IDynamicCastableGetInterfaceImplementation = 9, - ObjectiveCMarshalTryGetTaggedMemory = 10, - ObjectiveCMarshalGetIsTrackedReferenceCallback = 11, - ObjectiveCMarshalGetOnEnteredFinalizerQueueCallback = 12, - ObjectiveCMarshalGetUnhandledExceptionPropagationHandler = 13, + AppendExceptionStackFrame = 2, + OnFirstChanceException = 3, + OnUnhandledException = 4, + IDynamicCastableIsInterfaceImplemented = 5, + IDynamicCastableGetInterfaceImplementation = 6, + ObjectiveCMarshalTryGetTaggedMemory = 7, + ObjectiveCMarshalGetIsTrackedReferenceCallback = 8, + ObjectiveCMarshalGetOnEnteredFinalizerQueueCallback = 9, + ObjectiveCMarshalGetUnhandledExceptionPropagationHandler = 10, }; enum class AssociatedDataFlags : unsigned char diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs index 61f70e212483c..58192f68bca9c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs @@ -49,14 +49,6 @@ internal unsafe bool IsSzArray } } - // This is the classlib-provided "get array MethodTable" function that will be invoked whenever the runtime - // needs to know the base type of an array. - [RuntimeExport("GetSystemArrayEEType")] - private static unsafe MethodTable* GetSystemArrayEEType() - { - return MethodTable.Of(); - } - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] private static unsafe Array InternalCreate(RuntimeType elementType, int rank, int* pLengths, int* pLowerBounds) { diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/System/Array.cs b/src/coreclr/nativeaot/Test.CoreLib/src/System/Array.cs deleted file mode 100644 index 33e35805e4df4..0000000000000 --- a/src/coreclr/nativeaot/Test.CoreLib/src/System/Array.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime; - -using MethodTable = Internal.Runtime.MethodTable; - -namespace System -{ - public partial class Array - { - // This is the classlib-provided "get array MethodTable" function that will be invoked whenever the runtime - // needs to know the base type of an array. - [RuntimeExport("GetSystemArrayEEType")] - private static unsafe MethodTable* GetSystemArrayEEType() - { - return MethodTable.Of(); - } - } -} diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj b/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj index 1ef37ec04bca5..a676261c4d99f 100644 --- a/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj +++ b/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj @@ -226,7 +226,6 @@ - From a765dd876841d985793e3a8ec9a35281d2aeedc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= Date: Fri, 21 Jun 2024 18:13:36 +0200 Subject: [PATCH 5/5] Address comments --- .../src/System/Runtime/ExceptionHandling.cs | 13 ++++--------- .../src/System/Runtime/ExceptionIDs.cs | 16 +++++----------- .../src/System/Runtime/MethodTable.Runtime.cs | 7 +++++++ .../src/System/Runtime/TypeCast.cs | 6 +++--- .../src/System/Runtime/ExceptionIDs.cs | 16 +++++----------- .../src/System/RuntimeExceptionHelpers.cs | 18 ------------------ .../Internal/Runtime/MethodTable.Runtime.cs | 5 ----- .../src/System/RuntimeExceptionHelpers.cs | 12 ------------ 8 files changed, 24 insertions(+), 69 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs index 0e382b9d8579c..25a67bf7906d3 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs @@ -316,14 +316,8 @@ internal static Exception GetClasslibException(ExceptionIDs id, IntPtr address) Exception? e = id switch { ExceptionIDs.AccessViolation => new AccessViolationException(), - ExceptionIDs.Arithmetic => new ArithmeticException(), - ExceptionIDs.AmbiguousImplementation => new AmbiguousImplementationException(), - ExceptionIDs.ArrayTypeMismatch => new ArrayTypeMismatchException(), ExceptionIDs.DataMisaligned => new DataMisalignedException(), ExceptionIDs.DivideByZero => new DivideByZeroException(), - ExceptionIDs.EntrypointNotFound => new EntryPointNotFoundException(), - ExceptionIDs.IndexOutOfRange => new IndexOutOfRangeException(), - ExceptionIDs.InvalidCast => new InvalidCastException(), ExceptionIDs.NullReference => new NullReferenceException(), ExceptionIDs.OutOfMemory => new OutOfMemoryException(), ExceptionIDs.Overflow => new OverflowException(), @@ -342,12 +336,13 @@ internal static Exception GetClasslibException(ExceptionIDs id, IntPtr address) #if NATIVEAOT [StackTraceHidden] [RuntimeExport("RhExceptionHandling_FailedAllocation")] -#pragma warning disable IDE0060 public static void FailedAllocation(MethodTable* pEEType, bool fIsOverflow) -#pragma warning restore IDE0060 { ExceptionIDs exID = fIsOverflow ? ExceptionIDs.Overflow : ExceptionIDs.OutOfMemory; - throw RuntimeExceptionHelpers.GetRuntimeException(exID)!; + + // Throw the out of memory exception defined by the classlib, using the input MethodTable* + // to find the correct classlib. + throw pEEType->GetClasslibException(exID); } #endif // NATIVEAOT diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs index 764bd124d6774..d7e8df376476e 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs @@ -11,16 +11,10 @@ namespace System.Runtime enum ExceptionIDs { OutOfMemory = 1, - Arithmetic = 2, - ArrayTypeMismatch = 3, - DivideByZero = 4, - IndexOutOfRange = 5, - InvalidCast = 6, - Overflow = 7, - NullReference = 8, - AccessViolation = 9, - DataMisaligned = 10, - EntrypointNotFound = 11, - AmbiguousImplementation = 12, + DivideByZero = 2, + Overflow = 3, + NullReference = 4, + AccessViolation = 5, + DataMisaligned = 6 } } diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/MethodTable.Runtime.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/MethodTable.Runtime.cs index 8bd44f7fa0121..1c2c322531605 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/MethodTable.Runtime.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/MethodTable.Runtime.cs @@ -11,6 +11,13 @@ namespace Internal.Runtime // Extensions to MethodTable that are specific to the use in Runtime.Base. internal unsafe partial struct MethodTable { +#pragma warning disable CA1822 + internal Exception GetClasslibException(ExceptionIDs id) + { + return RuntimeExceptionHelpers.GetRuntimeException(id); + } +#pragma warning restore CA1822 + internal IntPtr GetClasslibFunction(ClassLibFunctionId id) { return (IntPtr)InternalCalls.RhpGetClasslibFunctionFromEEType((MethodTable*)Unsafe.AsPointer(ref this), id); diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs index b56f2a771eff8..33d3032b6e50e 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs @@ -382,7 +382,7 @@ private static unsafe object CheckCastInterface_Helper(MethodTable* pTargetType, { // If object type implements IDynamicInterfaceCastable then there's one more way to check whether it implements // the interface. - // This will throw NullReferenceException if obj is null. + Debug.Assert(obj is not null); if (!obj.GetMethodTable()->IsIDynamicInterfaceCastable || !IsInstanceOfInterfaceViaIDynamicInterfaceCastable(pTargetType, obj, throwing: true)) { @@ -872,7 +872,7 @@ private static unsafe object CheckCastArray(MethodTable* pTargetEEType, object o private static unsafe object IsInstanceOfVariantType(MethodTable* pTargetType, object obj) { - // This will throw NullReferenceException if obj is null. + Debug.Assert(obj is not null); if (!AreTypesAssignableInternal(obj.GetMethodTable(), pTargetType, AssignmentVariation.BoxedSource, null) && (!obj.GetMethodTable()->IsIDynamicInterfaceCastable || !IsInstanceOfInterfaceViaIDynamicInterfaceCastable(pTargetType, obj, throwing: false))) @@ -885,7 +885,7 @@ private static unsafe object IsInstanceOfVariantType(MethodTable* pTargetType, o private static unsafe object CheckCastVariantType(MethodTable* pTargetType, object obj) { - // This will throw NullReferenceException if obj is null. + Debug.Assert(obj is not null); if (!AreTypesAssignableInternal(obj.GetMethodTable(), pTargetType, AssignmentVariation.BoxedSource, null) && (!obj.GetMethodTable()->IsIDynamicInterfaceCastable || !IsInstanceOfInterfaceViaIDynamicInterfaceCastable(pTargetType, obj, throwing: true))) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs index 7fc0ad6a9dfeb..b22720ed325e8 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs @@ -6,16 +6,10 @@ namespace System.Runtime internal enum ExceptionIDs { OutOfMemory = 1, - Arithmetic = 2, - ArrayTypeMismatch = 3, - DivideByZero = 4, - IndexOutOfRange = 5, - InvalidCast = 6, - Overflow = 7, - NullReference = 8, - AccessViolation = 9, - DataMisaligned = 10, - EntrypointNotFound = 11, - AmbiguousImplementation = 12, + DivideByZero = 2, + Overflow = 3, + NullReference = 4, + AccessViolation = 5, + DataMisaligned = 6 } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs index 0ed5f375cc27c..4ed4798dc49d1 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs @@ -71,21 +71,9 @@ internal static class RuntimeExceptionHelpers return outOfMemoryException; - case ExceptionIDs.Arithmetic: - return new ArithmeticException(); - - case ExceptionIDs.ArrayTypeMismatch: - return new ArrayTypeMismatchException(); - case ExceptionIDs.DivideByZero: return new DivideByZeroException(); - case ExceptionIDs.IndexOutOfRange: - return new IndexOutOfRangeException(); - - case ExceptionIDs.InvalidCast: - return new InvalidCastException(); - case ExceptionIDs.Overflow: return new OverflowException(); @@ -99,12 +87,6 @@ internal static class RuntimeExceptionHelpers case ExceptionIDs.DataMisaligned: return new DataMisalignedException(); - case ExceptionIDs.EntrypointNotFound: - return new EntryPointNotFoundException(); - - case ExceptionIDs.AmbiguousImplementation: - return new AmbiguousImplementationException(); - default: FailFast("The runtime requires an exception for a case that this class library does not understand."); return null; diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/Internal/Runtime/MethodTable.Runtime.cs b/src/coreclr/nativeaot/Test.CoreLib/src/Internal/Runtime/MethodTable.Runtime.cs index 1bb7dcd62abd1..20654398f09ea 100644 --- a/src/coreclr/nativeaot/Test.CoreLib/src/Internal/Runtime/MethodTable.Runtime.cs +++ b/src/coreclr/nativeaot/Test.CoreLib/src/Internal/Runtime/MethodTable.Runtime.cs @@ -13,10 +13,5 @@ internal unsafe partial struct MethodTable { return MethodTable.Of(); } - - internal Exception GetClasslibException(ExceptionIDs id) - { - return RuntimeExceptionHelpers.GetRuntimeException(id); - } } } diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/System/RuntimeExceptionHelpers.cs b/src/coreclr/nativeaot/Test.CoreLib/src/System/RuntimeExceptionHelpers.cs index 8100d936e66b0..b218e70bb7342 100644 --- a/src/coreclr/nativeaot/Test.CoreLib/src/System/RuntimeExceptionHelpers.cs +++ b/src/coreclr/nativeaot/Test.CoreLib/src/System/RuntimeExceptionHelpers.cs @@ -43,21 +43,9 @@ public static Exception GetRuntimeException(ExceptionIDs id) case ExceptionIDs.OutOfMemory: return PreallocatedOutOfMemoryException.Instance; - case ExceptionIDs.Arithmetic: - return new ArithmeticException(); - - case ExceptionIDs.ArrayTypeMismatch: - return new ArrayTypeMismatchException(); - case ExceptionIDs.DivideByZero: return new DivideByZeroException(); - case ExceptionIDs.IndexOutOfRange: - return new IndexOutOfRangeException(); - - case ExceptionIDs.InvalidCast: - return new InvalidCastException(); - case ExceptionIDs.Overflow: return new OverflowException();