Initial commit
[mono.git] / mcs / class / referencesource / System / compmod / system / collections / generic / throwhelper.cs
1 namespace System {
2     // This file defines an internal class used to throw exceptions in BCL code.
3     // The main purpose is to reduce code size. 
4     // 
5     // The old way to throw an exception generates quite a lot IL code and assembly code.
6     // Following is an example:
7     //     C# source
8     //          throw new ArgumentNullException("key", SR.GetString("ArgumentNull_Key"));
9     //     IL code:
10     //          IL_0003:  ldstr      "key"
11     //          IL_0008:  ldstr      "ArgumentNull_Key"
12     //          IL_000d:  call       string System.Environment::GetResourceString(string)
13     //          IL_0012:  newobj     instance void System.ArgumentNullException::.ctor(string,string)
14     //          IL_0017:  throw
15     //    which is 21bytes in IL.
16     // 
17     // So we want to get rid of the ldstr and call to Environment.GetResource in IL.
18     // In order to do that, I created two enums: ExceptionResource, ExceptionArgument to represent the
19     // argument name and resource name in a small integer. The source code will be changed to 
20     //    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key, ExceptionResource.ArgumentNull_Key);
21     //
22     // The IL code will be 7 bytes.
23     //    IL_0008:  ldc.i4.4
24     //    IL_0009:  ldc.i4.4
25     //    IL_000a:  call       void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument)
26     //    IL_000f:  ldarg.0
27     //
28     // This will also reduce the Jitted code size a lot. 
29     //
30     // It is very important we do this for generic classes because we can easily generate the same code 
31     // multiple times for different instantiation. 
32     // 
33     // <STRIP>
34     // Jit will generates the code to throw exception at the end of a method, thus we can reduce working
35     // set if the user code will never throw an exception. However Jit doesn't know anything about the
36     // methods in ThrowHelper, so it will not moves the instructions to the end. 
37     // This is not a problem for ngened code because we will probably move the code based on profile data(hopefully.) 
38     //
39     // For jitted code, it doesn't make much difference. The only advantage of moving the code to the end is to 
40     // improve cache locality. Patrick pointed out this doesn't make much different on newer processor like P4.
41     // </STRIP>
42
43
44 #if !SILVERLIGHT
45     using System.Runtime.Serialization;
46 #endif
47
48     using System.Diagnostics;
49     internal static class ThrowHelper {    
50         internal static void ThrowWrongKeyTypeArgumentException(object key, Type targetType) {
51             throw new ArgumentException(SR.GetString(SR.Arg_WrongType, key, targetType), "key");
52         }
53
54         internal static void ThrowWrongValueTypeArgumentException(object value, Type targetType) {
55             throw new ArgumentException(SR.GetString(SR.Arg_WrongType, value, targetType), "value");
56         }
57
58         internal static void ThrowKeyNotFoundException() {
59             throw new System.Collections.Generic.KeyNotFoundException();
60         }
61         
62         internal static void ThrowArgumentException(ExceptionResource resource) {
63             throw new ArgumentException(SR.GetString(GetResourceName(resource)));
64         }
65
66         internal static void ThrowArgumentNullException(ExceptionArgument argument) {
67             throw new ArgumentNullException(GetArgumentName(argument));
68         }
69
70         internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) {
71             throw new ArgumentOutOfRangeException(GetArgumentName(argument));
72         }
73
74         internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) {
75             throw new ArgumentOutOfRangeException(GetArgumentName(argument), SR.GetString(GetResourceName(resource)));
76         }
77
78         internal static void ThrowInvalidOperationException(ExceptionResource resource) {
79             throw new InvalidOperationException(SR.GetString(GetResourceName(resource)));
80         }
81
82 #if !SILVERLIGHT
83         internal static void ThrowSerializationException(ExceptionResource resource) {
84             throw new SerializationException(SR.GetString(GetResourceName(resource)));
85         }
86 #endif
87         
88         internal static void ThrowNotSupportedException(ExceptionResource resource) {
89             throw new NotSupportedException(SR.GetString(GetResourceName(resource)));
90         }
91
92         // Allow nulls for reference types and Nullable<U>, but not for value types.
93         internal static void IfNullAndNullsAreIllegalThenThrow<T>(object value, ExceptionArgument argName) {
94             // Note that default(T) is not equal to null for value types except when T is Nullable<U>. 
95             if (value == null && !(default(T) == null))
96                 ThrowHelper.ThrowArgumentNullException(argName);
97         }
98
99         //
100         // This function will convert an ExceptionArgument enum value to the argument name string.
101         //
102         internal static string GetArgumentName(ExceptionArgument argument) {
103             string argumentName = null;
104
105             switch (argument) {
106                 case ExceptionArgument.array:
107                     argumentName = "array";
108                     break;
109
110                 case ExceptionArgument.arrayIndex:
111                     argumentName = "arrayIndex";
112                     break;
113
114                 case ExceptionArgument.capacity:
115                     argumentName = "capacity";
116                     break;
117
118                 case ExceptionArgument.collection:
119                     argumentName = "collection";
120                     break;
121
122                 case ExceptionArgument.converter:
123                     argumentName = "converter";
124                     break;
125
126                 case ExceptionArgument.count:
127                     argumentName = "count";
128                     break;
129
130                 case ExceptionArgument.dictionary:
131                     argumentName = "dictionary";
132                     break;
133
134                 case ExceptionArgument.index:
135                     argumentName = "index";
136                     break;
137
138                 case ExceptionArgument.info:
139                     argumentName = "info";
140                     break;
141
142                 case ExceptionArgument.key:
143                     argumentName = "key";
144                     break;
145
146                 case ExceptionArgument.match:
147                     argumentName = "match";
148                     break;
149
150                 case ExceptionArgument.obj:
151                     argumentName = "obj";
152                     break;
153
154                 case ExceptionArgument.queue:
155                     argumentName = "queue";
156                     break;
157
158                 case ExceptionArgument.stack:
159                     argumentName = "stack";
160                     break;
161
162                 case ExceptionArgument.startIndex:
163                     argumentName = "startIndex";
164                     break;
165
166                 case ExceptionArgument.value:
167                     argumentName = "value";
168                     break;
169
170                 case ExceptionArgument.item:
171                     argumentName = "item";
172                     break;
173
174                 default:
175                     Debug.Assert(false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
176                     return string.Empty;
177             }
178
179             return argumentName;
180         }
181
182         //
183         // This function will convert an ExceptionResource enum value to the resource string.
184         //
185         internal static string GetResourceName(ExceptionResource resource) {
186             string resourceName = null;
187
188             switch (resource) {
189                 case ExceptionResource.Argument_ImplementIComparable:
190                     resourceName = SR.Argument_ImplementIComparable;
191                     break;
192
193                 case ExceptionResource.Argument_AddingDuplicate:
194                     resourceName = SR.Argument_AddingDuplicate;
195                     break;
196
197                 case ExceptionResource.ArgumentOutOfRange_Index:
198                     resourceName = SR.ArgumentOutOfRange_Index;
199                     break;
200
201                 case ExceptionResource.ArgumentOutOfRange_NeedNonNegNum:
202                     resourceName = SR.ArgumentOutOfRange_NeedNonNegNum;
203                     break;
204
205                 case ExceptionResource.ArgumentOutOfRange_NeedNonNegNumRequired:
206                     resourceName = SR.ArgumentOutOfRange_NeedNonNegNumRequired;
207                     break;
208
209                 case ExceptionResource.ArgumentOutOfRange_SmallCapacity:
210                     resourceName = SR.ArgumentOutOfRange_SmallCapacity;
211                     break;
212
213                 case ExceptionResource.Arg_ArrayPlusOffTooSmall:
214                     resourceName = SR.Arg_ArrayPlusOffTooSmall;
215                     break;
216
217                 case ExceptionResource.Arg_RankMultiDimNotSupported:
218                     resourceName = SR.Arg_MultiRank;
219                     break;
220
221                 case ExceptionResource.Arg_NonZeroLowerBound:
222                     resourceName = SR.Arg_NonZeroLowerBound;
223                     break;
224
225                 case ExceptionResource.Argument_InvalidArrayType:
226                     resourceName = SR.Invalid_Array_Type;
227                     break;
228
229                 case ExceptionResource.Argument_InvalidOffLen:
230                     resourceName = SR.Argument_InvalidOffLen;
231                     break;
232
233                 case ExceptionResource.InvalidOperation_CannotRemoveFromStackOrQueue:
234                     resourceName = SR.InvalidOperation_CannotRemoveFromStackOrQueue;
235                     break;
236
237                 case ExceptionResource.InvalidOperation_EmptyCollection:
238                     resourceName = SR.InvalidOperation_EmptyCollection;
239                     break;
240
241                 case ExceptionResource.InvalidOperation_EmptyQueue:
242                     resourceName = SR.InvalidOperation_EmptyQueue;
243                     break;
244
245                 case ExceptionResource.InvalidOperation_EnumOpCantHappen:
246                     resourceName = SR.InvalidOperation_EnumOpCantHappen;
247                     break;
248
249                 case ExceptionResource.InvalidOperation_EnumFailedVersion:
250                     resourceName = SR.InvalidOperation_EnumFailedVersion;
251                     break;
252
253                 case ExceptionResource.InvalidOperation_EmptyStack:
254                     resourceName = SR.InvalidOperation_EmptyStack;
255                     break;
256
257                 case ExceptionResource.InvalidOperation_EnumNotStarted:
258                     resourceName = SR.InvalidOperation_EnumNotStarted;
259                     break;
260
261                 case ExceptionResource.InvalidOperation_EnumEnded:
262                     resourceName = SR.InvalidOperation_EnumEnded;
263                     break;
264
265                 case ExceptionResource.NotSupported_KeyCollectionSet:
266                     resourceName = SR.NotSupported_KeyCollectionSet;
267                     break;
268
269                 case ExceptionResource.NotSupported_SortedListNestedWrite:
270                     resourceName = SR.NotSupported_SortedListNestedWrite;
271                     break;
272
273 #if !SILVERLIGHT
274                 case ExceptionResource.Serialization_InvalidOnDeser:
275                     resourceName = SR.Serialization_InvalidOnDeser;
276                     break;
277
278                 case ExceptionResource.Serialization_MissingValues:
279                     resourceName = SR.Serialization_MissingValues;
280                     break;
281
282                 case ExceptionResource.Serialization_MismatchedCount:
283                     resourceName = SR.Serialization_MismatchedCount;
284                     break;
285 #endif
286
287                 case ExceptionResource.NotSupported_ValueCollectionSet:
288                     resourceName = SR.NotSupported_ValueCollectionSet;
289                     break;
290
291                 default:
292                     Debug.Assert(false, "The enum value is not defined, please checked ExceptionArgumentName Enum.");
293                     return string.Empty;
294             }
295
296             return resourceName;
297         }
298
299     }
300
301     //
302     // The convention for this enum is using the argument name as the enum name
303     // 
304     internal enum ExceptionArgument {
305         obj,
306         dictionary,
307         array,
308         info,
309         key,
310         collection,
311         match,
312         converter,
313         queue,
314         stack,
315         capacity,
316         index,
317         startIndex,
318         value,
319         count,
320         arrayIndex,
321         item,
322     }
323
324     //
325     // The convention for this enum is using the resource name as the enum name
326     // 
327     internal enum ExceptionResource {
328         Argument_ImplementIComparable,
329         ArgumentOutOfRange_NeedNonNegNum,
330         ArgumentOutOfRange_NeedNonNegNumRequired,
331         Arg_ArrayPlusOffTooSmall,
332         Argument_AddingDuplicate,
333         Serialization_InvalidOnDeser,
334         Serialization_MismatchedCount,
335         Serialization_MissingValues,
336         Arg_RankMultiDimNotSupported,
337         Arg_NonZeroLowerBound,
338         Argument_InvalidArrayType,
339         NotSupported_KeyCollectionSet,
340         ArgumentOutOfRange_SmallCapacity,
341         ArgumentOutOfRange_Index,
342         Argument_InvalidOffLen,
343         NotSupported_ReadOnlyCollection,
344         InvalidOperation_CannotRemoveFromStackOrQueue,
345         InvalidOperation_EmptyCollection,
346         InvalidOperation_EmptyQueue,
347         InvalidOperation_EnumOpCantHappen,
348         InvalidOperation_EnumFailedVersion,
349         InvalidOperation_EmptyStack,
350         InvalidOperation_EnumNotStarted,
351         InvalidOperation_EnumEnded,
352         NotSupported_SortedListNestedWrite,
353         NotSupported_ValueCollectionSet,
354     }
355 }
356
357