| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- // This file defines an internal class used to throw exceptions in BCL code.
- // The main purpose is to reduce code size.
- //
- // The old way to throw an exception generates quite a lot IL code and assembly code.
- // Following is an example:
- // C# source
- // throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key);
- // IL code:
- // IL_0003: ldstr "key"
- // IL_0008: ldstr "ArgumentNull_Key"
- // IL_000d: call string System.Environment::GetResourceString(string)
- // IL_0012: newobj instance void System.ArgumentNullException::.ctor(string,string)
- // IL_0017: throw
- // which is 21bytes in IL.
- //
- // So we want to get rid of the ldstr and call to Environment.GetResource in IL.
- // In order to do that, I created two enums: ExceptionResource, ExceptionArgument to represent the
- // argument name and resource name in a small integer. The source code will be changed to
- // ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key, ExceptionResource.ArgumentNull_Key);
- //
- // The IL code will be 7 bytes.
- // IL_0008: ldc.i4.4
- // IL_0009: ldc.i4.4
- // IL_000a: call void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument)
- // IL_000f: ldarg.0
- //
- // This will also reduce the Jitted code size a lot.
- //
- // It is very important we do this for generic classes because we can easily generate the same code
- // multiple times for different instantiation.
- //
- using System.Buffers;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
- using System.Runtime.Serialization;
- namespace System
- {
- [StackTraceHidden]
- internal static class ThrowHelper
- {
- internal static void ThrowArrayTypeMismatchException()
- {
- throw new ArrayTypeMismatchException();
- }
- internal static void ThrowInvalidTypeWithPointersNotSupported(Type targetType)
- {
- throw new ArgumentException(SR.Format(SR.Argument_InvalidTypeWithPointersNotSupported, targetType));
- }
- internal static void ThrowIndexOutOfRangeException()
- {
- throw new IndexOutOfRangeException();
- }
- internal static void ThrowArgumentOutOfRangeException()
- {
- throw new ArgumentOutOfRangeException();
- }
- internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument)
- {
- throw new ArgumentOutOfRangeException(GetArgumentName(argument));
- }
- private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
- {
- return new ArgumentOutOfRangeException(GetArgumentName(argument), GetResourceString(resource));
- }
- internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
- {
- throw GetArgumentOutOfRangeException(argument, resource);
- }
- internal static void ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index()
- {
- throw GetArgumentOutOfRangeException(ExceptionArgument.startIndex,
- ExceptionResource.ArgumentOutOfRange_Index);
- }
- internal static void ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count()
- {
- throw GetArgumentOutOfRangeException(ExceptionArgument.count,
- ExceptionResource.ArgumentOutOfRange_Count);
- }
- internal static void ThrowArgumentException_DestinationTooShort()
- {
- throw new ArgumentException(SR.Argument_DestinationTooShort);
- }
- internal static void ThrowArgumentException_OverlapAlignmentMismatch()
- {
- throw new ArgumentException(SR.Argument_OverlapAlignmentMismatch);
- }
- internal static void ThrowArgumentException_CannotExtractScalar(ExceptionArgument argument)
- {
- throw GetArgumentException(ExceptionResource.Argument_CannotExtractScalar, argument);
- }
- internal static void ThrowArgumentOutOfRange_IndexException()
- {
- throw GetArgumentOutOfRangeException(ExceptionArgument.index,
- ExceptionResource.ArgumentOutOfRange_Index);
- }
- internal static void ThrowIndexArgumentOutOfRange_NeedNonNegNumException()
- {
- throw GetArgumentOutOfRangeException(ExceptionArgument.index,
- ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
- }
- internal static void ThrowValueArgumentOutOfRange_NeedNonNegNumException()
- {
- throw GetArgumentOutOfRangeException(ExceptionArgument.value,
- ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
- }
- private static ArgumentException GetWrongKeyTypeArgumentException(object key, Type targetType)
- {
- return new ArgumentException(SR.Format(SR.Arg_WrongType, key, targetType), nameof(key));
- }
- internal static void ThrowWrongKeyTypeArgumentException(object key, Type targetType)
- {
- throw GetWrongKeyTypeArgumentException(key, targetType);
- }
- private static ArgumentException GetWrongValueTypeArgumentException(object value, Type targetType)
- {
- return new ArgumentException(SR.Format(SR.Arg_WrongType, value, targetType), nameof(value));
- }
- internal static void ThrowWrongValueTypeArgumentException(object value, Type targetType)
- {
- throw GetWrongValueTypeArgumentException(value, targetType);
- }
- private static ArgumentException GetAddingDuplicateWithKeyArgumentException(object key)
- {
- return new ArgumentException(SR.Format(SR.Argument_AddingDuplicate, key));
- }
- internal static void ThrowAddingDuplicateWithKeyArgumentException(object key)
- {
- throw GetAddingDuplicateWithKeyArgumentException(key);
- }
- private static KeyNotFoundException GetKeyNotFoundException(object key)
- {
- throw new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString()));
- }
- internal static void ThrowKeyNotFoundException(object key)
- {
- throw GetKeyNotFoundException(key);
- }
- internal static void ThrowArgumentException(ExceptionResource resource)
- {
- throw new ArgumentException(GetResourceString(resource));
- }
- private static ArgumentException GetArgumentException(ExceptionResource resource, ExceptionArgument argument)
- {
- return new ArgumentException(GetResourceString(resource), GetArgumentName(argument));
- }
- internal static void ThrowArgumentException(ExceptionResource resource, ExceptionArgument argument)
- {
- throw GetArgumentException(resource, argument);
- }
- internal static void ThrowAggregateException(List<Exception> exceptions)
- {
- throw new AggregateException(exceptions);
- }
- internal static void ThrowArgumentException_Argument_InvalidArrayType()
- {
- throw new ArgumentException(SR.Argument_InvalidArrayType);
- }
- internal static void ThrowArgumentNullException(ExceptionArgument argument)
- {
- throw new ArgumentNullException(GetArgumentName(argument));
- }
- internal static void ThrowInvalidOperationException(ExceptionResource resource)
- {
- throw new InvalidOperationException(GetResourceString(resource));
- }
- internal static void ThrowInvalidOperationException_OutstandingReferences()
- {
- throw new InvalidOperationException(SR.Memory_OutstandingReferences);
- }
- internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion()
- {
- throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
- }
- internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen()
- {
- throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
- }
- internal static void ThrowInvalidOperationException_InvalidOperation_EnumNotStarted()
- {
- throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted);
- }
- internal static void ThrowInvalidOperationException_InvalidOperation_EnumEnded()
- {
- throw new InvalidOperationException(SR.InvalidOperation_EnumEnded);
- }
- internal static void ThrowInvalidOperationException_InvalidOperation_NoValue()
- {
- throw new InvalidOperationException(SR.InvalidOperation_NoValue);
- }
- internal static void ThrowInvalidOperationException_ConcurrentOperationsNotSupported()
- {
- throw new InvalidOperationException(SR.InvalidOperation_ConcurrentOperationsNotSupported);
- }
- internal static void ThrowSerializationException(ExceptionResource resource)
- {
- throw new SerializationException(GetResourceString(resource));
- }
- internal static void ThrowObjectDisposedException(ExceptionResource resource)
- {
- throw new ObjectDisposedException(null, GetResourceString(resource));
- }
- internal static void ThrowNotSupportedException()
- {
- throw new NotSupportedException();
- }
- internal static void ThrowNotSupportedException(ExceptionResource resource)
- {
- throw new NotSupportedException(GetResourceString(resource));
- }
- private static Exception GetArraySegmentCtorValidationFailedException(Array array, int offset, int count)
- {
- if (array == null)
- return new ArgumentNullException(nameof(array));
- if (offset < 0)
- return new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum);
- if (count < 0)
- return new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
- Debug.Assert(array.Length - offset < count);
- return new ArgumentException(SR.Argument_InvalidOffLen);
- }
- internal static void ThrowArraySegmentCtorValidationFailedExceptions(Array array, int offset, int count)
- {
- throw GetArraySegmentCtorValidationFailedException(array, offset, count);
- }
- internal static void ThrowFormatException_BadFormatSpecifier()
- {
- throw new FormatException(SR.Argument_BadFormatSpecifier);
- }
- internal static void ThrowArgumentOutOfRangeException_PrecisionTooLarge()
- {
- throw new ArgumentOutOfRangeException("precision", SR.Format(SR.Argument_PrecisionTooLarge, StandardFormat.MaxPrecision));
- }
- internal static void ThrowArgumentOutOfRangeException_SymbolDoesNotFit()
- {
- throw new ArgumentOutOfRangeException("symbol", SR.Argument_BadFormatSpecifier);
- }
- // Allow nulls for reference types and Nullable<U>, but not for value types.
- // Aggressively inline so the jit evaluates the if in place and either drops the call altogether
- // Or just leaves null test and call to the Non-returning ThrowHelper.ThrowArgumentNullException
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void IfNullAndNullsAreIllegalThenThrow<T>(object value, ExceptionArgument argName)
- {
- // Note that default(T) is not equal to null for value types except when T is Nullable<U>.
- if (!(default(T) == null) && value == null)
- ThrowHelper.ThrowArgumentNullException(argName);
- }
- private static string GetArgumentName(ExceptionArgument argument)
- {
- switch (argument)
- {
- case ExceptionArgument.obj:
- return "obj";
- case ExceptionArgument.dictionary:
- return "dictionary";
- case ExceptionArgument.array:
- return "array";
- case ExceptionArgument.info:
- return "info";
- case ExceptionArgument.key:
- return "key";
- case ExceptionArgument.text:
- return "text";
- case ExceptionArgument.values:
- return "values";
- case ExceptionArgument.value:
- return "value";
- case ExceptionArgument.startIndex:
- return "startIndex";
- case ExceptionArgument.task:
- return "task";
- case ExceptionArgument.ch:
- return "ch";
- case ExceptionArgument.s:
- return "s";
- case ExceptionArgument.input:
- return "input";
- case ExceptionArgument.ownedMemory:
- return "ownedMemory";
- case ExceptionArgument.list:
- return "list";
- case ExceptionArgument.index:
- return "index";
- case ExceptionArgument.capacity:
- return "capacity";
- case ExceptionArgument.collection:
- return "collection";
- case ExceptionArgument.item:
- return "item";
- case ExceptionArgument.converter:
- return "converter";
- case ExceptionArgument.match:
- return "match";
- case ExceptionArgument.count:
- return "count";
- case ExceptionArgument.action:
- return "action";
- case ExceptionArgument.comparison:
- return "comparison";
- case ExceptionArgument.exceptions:
- return "exceptions";
- case ExceptionArgument.exception:
- return "exception";
- case ExceptionArgument.pointer:
- return "pointer";
- case ExceptionArgument.start:
- return "start";
- case ExceptionArgument.format:
- return "format";
- case ExceptionArgument.culture:
- return "culture";
- case ExceptionArgument.comparer:
- return "comparer";
- case ExceptionArgument.comparable:
- return "comparable";
- case ExceptionArgument.source:
- return "source";
- case ExceptionArgument.state:
- return "state";
- case ExceptionArgument.length:
- return "length";
- case ExceptionArgument.comparisonType:
- return "comparisonType";
- case ExceptionArgument.manager:
- return "manager";
- case ExceptionArgument.sourceBytesToCopy:
- return "sourceBytesToCopy";
- case ExceptionArgument.callBack:
- return "callBack";
- case ExceptionArgument.creationOptions:
- return "creationOptions";
- case ExceptionArgument.function:
- return "function";
- case ExceptionArgument.scheduler:
- return "scheduler";
- case ExceptionArgument.continuationAction:
- return "continuationAction";
- case ExceptionArgument.continuationFunction:
- return "continuationFunction";
- case ExceptionArgument.tasks:
- return "tasks";
- case ExceptionArgument.asyncResult:
- return "asyncResult";
- case ExceptionArgument.beginMethod:
- return "beginMethod";
- case ExceptionArgument.endMethod:
- return "endMethod";
- case ExceptionArgument.endFunction:
- return "endFunction";
- case ExceptionArgument.cancellationToken:
- return "cancellationToken";
- case ExceptionArgument.continuationOptions:
- return "continuationOptions";
- case ExceptionArgument.delay:
- return "delay";
- case ExceptionArgument.millisecondsDelay:
- return "millisecondsDelay";
- case ExceptionArgument.millisecondsTimeout:
- return "millisecondsTimeout";
- case ExceptionArgument.stateMachine:
- return "stateMachine";
- case ExceptionArgument.timeout:
- return "timeout";
- default:
- Debug.Fail("The enum value is not defined, please check the ExceptionArgument Enum.");
- return "";
- }
- }
- private static string GetResourceString(ExceptionResource resource)
- {
- switch (resource)
- {
- case ExceptionResource.Argument_InvalidArgumentForComparison:
- return SR.Argument_InvalidArgumentForComparison;
- case ExceptionResource.ArgumentOutOfRange_Index:
- return SR.ArgumentOutOfRange_Index;
- case ExceptionResource.ArgumentOutOfRange_Count:
- return SR.ArgumentOutOfRange_Count;
- case ExceptionResource.Arg_ArrayPlusOffTooSmall:
- return SR.Arg_ArrayPlusOffTooSmall;
- case ExceptionResource.NotSupported_ReadOnlyCollection:
- return SR.NotSupported_ReadOnlyCollection;
- case ExceptionResource.Arg_RankMultiDimNotSupported:
- return SR.Arg_RankMultiDimNotSupported;
- case ExceptionResource.Arg_NonZeroLowerBound:
- return SR.Arg_NonZeroLowerBound;
- case ExceptionResource.ArgumentOutOfRange_ListInsert:
- return SR.ArgumentOutOfRange_ListInsert;
- case ExceptionResource.ArgumentOutOfRange_NeedNonNegNum:
- return SR.ArgumentOutOfRange_NeedNonNegNum;
- case ExceptionResource.ArgumentOutOfRange_SmallCapacity:
- return SR.ArgumentOutOfRange_SmallCapacity;
- case ExceptionResource.Argument_InvalidOffLen:
- return SR.Argument_InvalidOffLen;
- case ExceptionResource.Argument_CannotExtractScalar:
- return SR.Argument_CannotExtractScalar;
- case ExceptionResource.ArgumentOutOfRange_BiggerThanCollection:
- return SR.ArgumentOutOfRange_BiggerThanCollection;
- case ExceptionResource.Serialization_MissingKeys:
- return SR.Serialization_MissingKeys;
- case ExceptionResource.Serialization_NullKey:
- return SR.Serialization_NullKey;
- case ExceptionResource.NotSupported_KeyCollectionSet:
- return SR.NotSupported_KeyCollectionSet;
- case ExceptionResource.NotSupported_ValueCollectionSet:
- return SR.NotSupported_ValueCollectionSet;
- case ExceptionResource.InvalidOperation_NullArray:
- return SR.InvalidOperation_NullArray;
- case ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted:
- return SR.TaskT_TransitionToFinal_AlreadyCompleted;
- case ExceptionResource.TaskCompletionSourceT_TrySetException_NullException:
- return SR.TaskCompletionSourceT_TrySetException_NullException;
- case ExceptionResource.TaskCompletionSourceT_TrySetException_NoExceptions:
- return SR.TaskCompletionSourceT_TrySetException_NoExceptions;
- case ExceptionResource.NotSupported_StringComparison:
- return SR.NotSupported_StringComparison;
- case ExceptionResource.ConcurrentCollection_SyncRoot_NotSupported:
- return SR.ConcurrentCollection_SyncRoot_NotSupported;
- case ExceptionResource.Task_MultiTaskContinuation_NullTask:
- return SR.Task_MultiTaskContinuation_NullTask;
- case ExceptionResource.InvalidOperation_WrongAsyncResultOrEndCalledMultiple:
- return SR.InvalidOperation_WrongAsyncResultOrEndCalledMultiple;
- case ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList:
- return SR.Task_MultiTaskContinuation_EmptyTaskList;
- case ExceptionResource.Task_Start_TaskCompleted:
- return SR.Task_Start_TaskCompleted;
- case ExceptionResource.Task_Start_Promise:
- return SR.Task_Start_Promise;
- case ExceptionResource.Task_Start_ContinuationTask:
- return SR.Task_Start_ContinuationTask;
- case ExceptionResource.Task_Start_AlreadyStarted:
- return SR.Task_Start_AlreadyStarted;
- case ExceptionResource.Task_RunSynchronously_Continuation:
- return SR.Task_RunSynchronously_Continuation;
- case ExceptionResource.Task_RunSynchronously_Promise:
- return SR.Task_RunSynchronously_Promise;
- case ExceptionResource.Task_RunSynchronously_TaskCompleted:
- return SR.Task_RunSynchronously_TaskCompleted;
- case ExceptionResource.Task_RunSynchronously_AlreadyStarted:
- return SR.Task_RunSynchronously_AlreadyStarted;
- case ExceptionResource.AsyncMethodBuilder_InstanceNotInitialized:
- return SR.AsyncMethodBuilder_InstanceNotInitialized;
- case ExceptionResource.Task_ContinueWith_ESandLR:
- return SR.Task_ContinueWith_ESandLR;
- case ExceptionResource.Task_ContinueWith_NotOnAnything:
- return SR.Task_ContinueWith_NotOnAnything;
- case ExceptionResource.Task_Delay_InvalidDelay:
- return SR.Task_Delay_InvalidDelay;
- case ExceptionResource.Task_Delay_InvalidMillisecondsDelay:
- return SR.Task_Delay_InvalidMillisecondsDelay;
- case ExceptionResource.Task_Dispose_NotCompleted:
- return SR.Task_Dispose_NotCompleted;
- case ExceptionResource.Task_ThrowIfDisposed:
- return SR.Task_ThrowIfDisposed;
- case ExceptionResource.Task_WaitMulti_NullTask:
- return SR.Task_WaitMulti_NullTask;
- default:
- Debug.Assert(false,
- "The enum value is not defined, please check the ExceptionResource Enum.");
- return "";
- }
- }
- }
- //
- // The convention for this enum is using the argument name as the enum name
- //
- internal enum ExceptionArgument
- {
- obj,
- dictionary,
- array,
- info,
- key,
- text,
- values,
- value,
- startIndex,
- task,
- ch,
- s,
- input,
- ownedMemory,
- list,
- index,
- capacity,
- collection,
- item,
- converter,
- match,
- count,
- action,
- comparison,
- exceptions,
- exception,
- pointer,
- start,
- format,
- culture,
- comparer,
- comparable,
- source,
- state,
- length,
- comparisonType,
- manager,
- sourceBytesToCopy,
- callBack,
- creationOptions,
- function,
- scheduler,
- continuationAction,
- continuationFunction,
- tasks,
- asyncResult,
- beginMethod,
- endMethod,
- endFunction,
- cancellationToken,
- continuationOptions,
- delay,
- millisecondsDelay,
- millisecondsTimeout,
- stateMachine,
- timeout,
- }
- //
- // The convention for this enum is using the resource name as the enum name
- //
- internal enum ExceptionResource
- {
- Argument_InvalidArgumentForComparison,
- ArgumentOutOfRange_Index,
- ArgumentOutOfRange_Count,
- Arg_ArrayPlusOffTooSmall,
- NotSupported_ReadOnlyCollection,
- Arg_RankMultiDimNotSupported,
- Arg_NonZeroLowerBound,
- ArgumentOutOfRange_ListInsert,
- ArgumentOutOfRange_NeedNonNegNum,
- ArgumentOutOfRange_SmallCapacity,
- Argument_InvalidOffLen,
- Argument_CannotExtractScalar,
- ArgumentOutOfRange_BiggerThanCollection,
- Serialization_MissingKeys,
- Serialization_NullKey,
- NotSupported_KeyCollectionSet,
- NotSupported_ValueCollectionSet,
- InvalidOperation_NullArray,
- TaskT_TransitionToFinal_AlreadyCompleted,
- TaskCompletionSourceT_TrySetException_NullException,
- TaskCompletionSourceT_TrySetException_NoExceptions,
- NotSupported_StringComparison,
- ConcurrentCollection_SyncRoot_NotSupported,
- Task_MultiTaskContinuation_NullTask,
- InvalidOperation_WrongAsyncResultOrEndCalledMultiple,
- Task_MultiTaskContinuation_EmptyTaskList,
- Task_Start_TaskCompleted,
- Task_Start_Promise,
- Task_Start_ContinuationTask,
- Task_Start_AlreadyStarted,
- Task_RunSynchronously_Continuation,
- Task_RunSynchronously_Promise,
- Task_RunSynchronously_TaskCompleted,
- Task_RunSynchronously_AlreadyStarted,
- AsyncMethodBuilder_InstanceNotInitialized,
- Task_ContinueWith_ESandLR,
- Task_ContinueWith_NotOnAnything,
- Task_Delay_InvalidDelay,
- Task_Delay_InvalidMillisecondsDelay,
- Task_Dispose_NotCompleted,
- Task_ThrowIfDisposed,
- Task_WaitMulti_NullTask,
- }
- }
|