ba6d73260b3697fbb57325e0698774ea677c0c61
[platform/upstream/dotnet/runtime.git] /
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3
4 using System;
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.Diagnostics.CodeAnalysis;
8 using System.Globalization;
9 using System.Reflection;
10 using System.Reflection.Emit;
11 using System.Runtime.Serialization.DataContracts;
12
13 namespace System.Runtime.Serialization
14 {
15     internal sealed class CodeGenerator
16     {
17         private static MethodInfo? s_getTypeFromHandle;
18         private static MethodInfo GetTypeFromHandle
19         {
20             get
21             {
22                 if (s_getTypeFromHandle == null)
23                 {
24                     s_getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle");
25                     Debug.Assert(s_getTypeFromHandle != null);
26                 }
27                 return s_getTypeFromHandle;
28             }
29         }
30
31         private static MethodInfo? s_objectEquals;
32         private static MethodInfo ObjectEquals
33         {
34             get
35             {
36                 if (s_objectEquals == null)
37                 {
38                     s_objectEquals = typeof(object).GetMethod("Equals", BindingFlags.Public | BindingFlags.Static);
39                     Debug.Assert(s_objectEquals != null);
40                 }
41                 return s_objectEquals;
42             }
43         }
44
45         private static MethodInfo? s_arraySetValue;
46         private static MethodInfo ArraySetValue
47         {
48             get
49             {
50                 if (s_arraySetValue == null)
51                 {
52                     s_arraySetValue = typeof(Array).GetMethod("SetValue", new Type[] { typeof(object), typeof(int) });
53                     Debug.Assert(s_arraySetValue != null);
54                 }
55                 return s_arraySetValue;
56             }
57         }
58
59         private static MethodInfo? s_objectToString;
60         private static MethodInfo ObjectToString
61         {
62             get
63             {
64                 if (s_objectToString == null)
65                 {
66                     s_objectToString = typeof(object).GetMethod("ToString", Type.EmptyTypes);
67                     Debug.Assert(s_objectToString != null);
68                 }
69                 return s_objectToString;
70             }
71         }
72
73         private static MethodInfo? s_stringFormat;
74         private static MethodInfo StringFormat
75         {
76             get
77             {
78                 if (s_stringFormat == null)
79                 {
80                     s_stringFormat = typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object[]) });
81                     Debug.Assert(s_stringFormat != null);
82                 }
83                 return s_stringFormat;
84             }
85         }
86
87         [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
88             Justification = "The trimmer will never remove the Invoke method from delegates.")]
89         internal static MethodInfo GetInvokeMethod(Type delegateType)
90         {
91             Debug.Assert(typeof(Delegate).IsAssignableFrom(delegateType));
92             return delegateType.GetMethod("Invoke")!;
93         }
94
95         private Type _delegateType = null!; // initialized in BeginMethod
96
97         private static Module? s_serializationModule;
98         private static Module SerializationModule => s_serializationModule ??= typeof(CodeGenerator).Module;   // could to be replaced by different dll that has SkipVerification set to false
99
100         private DynamicMethod _dynamicMethod = null!; // initialized in BeginMethod
101
102         private ILGenerator _ilGen = null!; // initialized in BeginMethod
103         private List<ArgBuilder> _argList = null!; // initialized in BeginMethod
104         private Stack<object> _blockStack = null!; // initialized in BeginMethod
105         private Label _methodEndLabel;
106
107         private LocalBuilder? _stringFormatArray;
108
109         internal CodeGenerator() { }
110
111         internal void BeginMethod(DynamicMethod dynamicMethod, Type delegateType, Type[] argTypes)
112         {
113             _dynamicMethod = dynamicMethod;
114             _ilGen = _dynamicMethod.GetILGenerator();
115             _delegateType = delegateType;
116
117             InitILGeneration(argTypes);
118         }
119
120         [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
121         internal void BeginMethod(string methodName, Type delegateType, bool allowPrivateMemberAccess)
122         {
123             MethodInfo signature = GetInvokeMethod(delegateType);
124             ParameterInfo[] parameters = signature.GetParameters();
125             Type[] paramTypes = new Type[parameters.Length];
126             for (int i = 0; i < parameters.Length; i++)
127                 paramTypes[i] = parameters[i].ParameterType;
128             BeginMethod(signature.ReturnType, methodName, paramTypes, allowPrivateMemberAccess);
129             _delegateType = delegateType;
130         }
131
132         [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
133         private void BeginMethod(Type returnType, string methodName, Type[] argTypes, bool allowPrivateMemberAccess)
134         {
135             _dynamicMethod = new DynamicMethod(methodName, returnType, argTypes, SerializationModule, allowPrivateMemberAccess);
136
137             _ilGen = _dynamicMethod.GetILGenerator();
138
139             InitILGeneration(argTypes);
140         }
141
142         private void InitILGeneration(Type[] argTypes)
143         {
144             _methodEndLabel = _ilGen.DefineLabel();
145             _blockStack = new Stack<object>();
146             _argList = new List<ArgBuilder>();
147             for (int i = 0; i < argTypes.Length; i++)
148                 _argList.Add(new ArgBuilder(i, argTypes[i]));
149         }
150
151         internal Delegate EndMethod()
152         {
153             MarkLabel(_methodEndLabel);
154             Ret();
155
156             Delegate? retVal;
157             retVal = _dynamicMethod.CreateDelegate(_delegateType);
158             _dynamicMethod = null!;
159             _delegateType = null!;
160
161             _ilGen = null!;
162             _blockStack = null!;
163             _argList = null!;
164             return retVal;
165         }
166
167         internal MethodInfo CurrentMethod
168         {
169             get
170             {
171                 return _dynamicMethod;
172             }
173         }
174
175         internal ArgBuilder GetArg(int index)
176         {
177             return _argList[index];
178         }
179
180         internal static Type GetVariableType(object var)
181         {
182             if (var is ArgBuilder argBuilder)
183                 return argBuilder.ArgType;
184             else if (var is LocalBuilder localBuilder)
185                 return localBuilder.LocalType;
186             else
187                 return var.GetType();
188         }
189
190         internal LocalBuilder DeclareLocal(Type type, object initialValue)
191         {
192             LocalBuilder local = DeclareLocal(type);
193             Load(initialValue);
194             Store(local);
195             return local;
196         }
197
198         internal LocalBuilder DeclareLocal(Type type)
199         {
200             return DeclareLocal(type, false);
201         }
202
203         internal LocalBuilder DeclareLocal(Type type, bool isPinned)
204         {
205             return _ilGen.DeclareLocal(type, isPinned);
206         }
207
208         internal void Set(LocalBuilder local, object value)
209         {
210             Load(value);
211             Store(local);
212         }
213
214         internal object For(LocalBuilder? local, object? start, object? end)
215         {
216             ForState forState = new ForState(local, DefineLabel(), DefineLabel(), end);
217             if (forState.Index != null)
218             {
219                 Load(start);
220                 Stloc(forState.Index);
221                 Br(forState.TestLabel);
222             }
223             MarkLabel(forState.BeginLabel);
224             _blockStack.Push(forState);
225             return forState;
226         }
227
228         internal void EndFor()
229         {
230             object stackTop = _blockStack.Pop();
231             ForState? forState = stackTop as ForState;
232             if (forState == null)
233                 ThrowMismatchException(stackTop);
234
235             if (forState.Index != null)
236             {
237                 Ldloc(forState.Index);
238                 Ldc(1);
239                 Add();
240                 Stloc(forState.Index);
241                 MarkLabel(forState.TestLabel);
242                 Ldloc(forState.Index);
243                 Load(forState.End);
244                 if (GetVariableType(forState.End!).IsArray)
245                     Ldlen();
246                 Blt(forState.BeginLabel);
247             }
248             else
249                 Br(forState.BeginLabel);
250             if (forState.RequiresEndLabel)
251                 MarkLabel(forState.EndLabel);
252         }
253
254         internal void Break(object forState)
255         {
256             InternalBreakFor(forState, OpCodes.Br);
257         }
258
259         internal void IfFalseBreak(object forState)
260         {
261             InternalBreakFor(forState, OpCodes.Brfalse);
262         }
263
264         internal void InternalBreakFor(object userForState, OpCode branchInstruction)
265         {
266             foreach (object block in _blockStack)
267             {
268                 if (block == userForState && block is ForState forState)
269                 {
270                     if (!forState.RequiresEndLabel)
271                     {
272                         forState.EndLabel = DefineLabel();
273                         forState.RequiresEndLabel = true;
274                     }
275
276                     _ilGen.Emit(branchInstruction, forState.EndLabel);
277                     break;
278                 }
279             }
280         }
281
282         internal void ForEach(LocalBuilder local, Type elementType,
283             LocalBuilder enumerator, MethodInfo getCurrentMethod)
284         {
285             ForState forState = new ForState(local, DefineLabel(), DefineLabel(), enumerator);
286
287             Br(forState.TestLabel);
288             MarkLabel(forState.BeginLabel);
289
290             Call(enumerator, getCurrentMethod);
291
292             ConvertValue(elementType, GetVariableType(local));
293             Stloc(local);
294             _blockStack.Push(forState);
295         }
296
297         internal void EndForEach(MethodInfo moveNextMethod)
298         {
299             object stackTop = _blockStack.Pop();
300             ForState? forState = stackTop as ForState;
301             if (forState == null)
302                 ThrowMismatchException(stackTop);
303
304             MarkLabel(forState.TestLabel);
305
306             object? enumerator = forState.End;
307             Call(enumerator, moveNextMethod);
308
309
310             Brtrue(forState.BeginLabel);
311             if (forState.RequiresEndLabel)
312                 MarkLabel(forState.EndLabel);
313         }
314
315         internal void IfNotDefaultValue(object value)
316         {
317             Type type = GetVariableType(value);
318             TypeCode typeCode = Type.GetTypeCode(type);
319             if ((typeCode == TypeCode.Object && type.IsValueType) ||
320                 typeCode == TypeCode.DateTime || typeCode == TypeCode.Decimal)
321             {
322                 LoadDefaultValue(type);
323                 ConvertValue(type, Globals.TypeOfObject);
324                 Load(value);
325                 ConvertValue(type, Globals.TypeOfObject);
326                 Call(ObjectEquals);
327                 IfNot();
328             }
329             else
330             {
331                 LoadDefaultValue(type);
332                 Load(value);
333                 If(Cmp.NotEqualTo);
334             }
335         }
336
337         internal void If()
338         {
339             InternalIf(false);
340         }
341
342         internal void IfNot()
343         {
344             InternalIf(true);
345         }
346
347         private static OpCode GetBranchCode(Cmp cmp)
348         {
349             switch (cmp)
350             {
351                 case Cmp.LessThan:
352                     return OpCodes.Bge;
353                 case Cmp.EqualTo:
354                     return OpCodes.Bne_Un;
355                 case Cmp.LessThanOrEqualTo:
356                     return OpCodes.Bgt;
357                 case Cmp.GreaterThan:
358                     return OpCodes.Ble;
359                 case Cmp.NotEqualTo:
360                     return OpCodes.Beq;
361                 default:
362                     DiagnosticUtility.DebugAssert(cmp == Cmp.GreaterThanOrEqualTo, "Unexpected cmp");
363                     return OpCodes.Blt;
364             }
365         }
366
367         internal void If(Cmp cmpOp)
368         {
369             IfState ifState = new IfState();
370             ifState.EndIf = DefineLabel();
371             ifState.ElseBegin = DefineLabel();
372             _ilGen.Emit(GetBranchCode(cmpOp), ifState.ElseBegin);
373             _blockStack.Push(ifState);
374         }
375
376
377         internal void If(object value1, Cmp cmpOp, object? value2)
378         {
379             Load(value1);
380             Load(value2);
381             If(cmpOp);
382         }
383         internal void Else()
384         {
385             IfState ifState = PopIfState();
386             Br(ifState.EndIf);
387             MarkLabel(ifState.ElseBegin);
388
389             ifState.ElseBegin = ifState.EndIf;
390             _blockStack.Push(ifState);
391         }
392
393         internal void ElseIf(object value1, Cmp cmpOp, object value2)
394         {
395             IfState ifState = (IfState)_blockStack.Pop();
396             Br(ifState.EndIf);
397             MarkLabel(ifState.ElseBegin);
398
399             Load(value1);
400             Load(value2);
401             ifState.ElseBegin = DefineLabel();
402
403             _ilGen.Emit(GetBranchCode(cmpOp), ifState.ElseBegin);
404             _blockStack.Push(ifState);
405         }
406
407
408         internal void EndIf()
409         {
410             IfState ifState = PopIfState();
411             if (!ifState.ElseBegin.Equals(ifState.EndIf))
412                 MarkLabel(ifState.ElseBegin);
413             MarkLabel(ifState.EndIf);
414         }
415
416         internal static void VerifyParameterCount(MethodInfo methodInfo, int expectedCount)
417         {
418             if (methodInfo.GetParameters().Length != expectedCount)
419                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ParameterCountMismatch, methodInfo.Name, methodInfo.GetParameters().Length, expectedCount)));
420         }
421
422         internal void Call(object? thisObj, MethodInfo methodInfo)
423         {
424             VerifyParameterCount(methodInfo, 0);
425             LoadThis(thisObj, methodInfo);
426             Call(methodInfo);
427         }
428
429         internal void Call(object? thisObj, MethodInfo methodInfo, object? param1)
430         {
431             VerifyParameterCount(methodInfo, 1);
432             LoadThis(thisObj, methodInfo);
433             LoadParam(param1, 1, methodInfo);
434             Call(methodInfo);
435         }
436
437         internal void Call(object? thisObj, MethodInfo methodInfo, object? param1, object? param2)
438         {
439             VerifyParameterCount(methodInfo, 2);
440             LoadThis(thisObj, methodInfo);
441             LoadParam(param1, 1, methodInfo);
442             LoadParam(param2, 2, methodInfo);
443             Call(methodInfo);
444         }
445
446         internal void Call(object? thisObj, MethodInfo methodInfo, object? param1, object? param2, object? param3)
447         {
448             VerifyParameterCount(methodInfo, 3);
449             LoadThis(thisObj, methodInfo);
450             LoadParam(param1, 1, methodInfo);
451             LoadParam(param2, 2, methodInfo);
452             LoadParam(param3, 3, methodInfo);
453             Call(methodInfo);
454         }
455
456         internal void Call(object? thisObj, MethodInfo methodInfo, object? param1, object? param2, object? param3, object? param4)
457         {
458             VerifyParameterCount(methodInfo, 4);
459             LoadThis(thisObj, methodInfo);
460             LoadParam(param1, 1, methodInfo);
461             LoadParam(param2, 2, methodInfo);
462             LoadParam(param3, 3, methodInfo);
463             LoadParam(param4, 4, methodInfo);
464             Call(methodInfo);
465         }
466
467         internal void Call(object? thisObj, MethodInfo methodInfo, object? param1, object? param2, object? param3, object? param4, object? param5)
468         {
469             VerifyParameterCount(methodInfo, 5);
470             LoadThis(thisObj, methodInfo);
471             LoadParam(param1, 1, methodInfo);
472             LoadParam(param2, 2, methodInfo);
473             LoadParam(param3, 3, methodInfo);
474             LoadParam(param4, 4, methodInfo);
475             LoadParam(param5, 5, methodInfo);
476             Call(methodInfo);
477         }
478
479         internal void Call(object? thisObj, MethodInfo methodInfo, object? param1, object? param2, object? param3, object? param4, object? param5, object? param6)
480         {
481             VerifyParameterCount(methodInfo, 6);
482             LoadThis(thisObj, methodInfo);
483             LoadParam(param1, 1, methodInfo);
484             LoadParam(param2, 2, methodInfo);
485             LoadParam(param3, 3, methodInfo);
486             LoadParam(param4, 4, methodInfo);
487             LoadParam(param5, 5, methodInfo);
488             LoadParam(param6, 6, methodInfo);
489             Call(methodInfo);
490         }
491
492         internal void Call(MethodInfo methodInfo)
493         {
494             if (methodInfo.IsVirtual && !methodInfo.DeclaringType!.IsValueType)
495             {
496                 _ilGen.Emit(OpCodes.Callvirt, methodInfo);
497             }
498             else if (methodInfo.IsStatic)
499             {
500                 _ilGen.Emit(OpCodes.Call, methodInfo);
501             }
502             else
503             {
504                 _ilGen.Emit(OpCodes.Call, methodInfo);
505             }
506         }
507
508         internal void Call(ConstructorInfo ctor)
509         {
510             _ilGen.Emit(OpCodes.Call, ctor);
511         }
512
513         internal void New(ConstructorInfo constructorInfo)
514         {
515             _ilGen.Emit(OpCodes.Newobj, constructorInfo);
516         }
517
518         internal void InitObj(Type valueType)
519         {
520             _ilGen.Emit(OpCodes.Initobj, valueType);
521         }
522
523         internal void NewArray(Type elementType, object len)
524         {
525             Load(len);
526             _ilGen.Emit(OpCodes.Newarr, elementType);
527         }
528
529         internal void LoadArrayElement(object obj, object? arrayIndex)
530         {
531             Type objType = GetVariableType(obj).GetElementType()!;
532             Load(obj);
533             Load(arrayIndex);
534             if (IsStruct(objType))
535             {
536                 Ldelema(objType);
537                 Ldobj(objType);
538             }
539             else
540                 Ldelem(objType);
541         }
542
543         internal void StoreArrayElement(object obj, object arrayIndex, object value)
544         {
545             Type arrayType = GetVariableType(obj);
546             if (arrayType == Globals.TypeOfArray)
547             {
548                 Call(obj, ArraySetValue, value, arrayIndex);
549             }
550             else
551             {
552                 Type objType = arrayType.GetElementType()!;
553                 Load(obj);
554                 Load(arrayIndex);
555                 if (IsStruct(objType))
556                     Ldelema(objType);
557                 Load(value);
558                 ConvertValue(GetVariableType(value), objType);
559                 if (IsStruct(objType))
560                     Stobj(objType);
561                 else
562                     Stelem(objType);
563             }
564         }
565
566         private static bool IsStruct(Type objType)
567         {
568             return objType.IsValueType && !objType.IsPrimitive;
569         }
570
571         internal Type LoadMember(MemberInfo memberInfo)
572         {
573             Type? memberType;
574             if (memberInfo is FieldInfo fieldInfo)
575             {
576                 memberType = fieldInfo.FieldType;
577                 if (fieldInfo.IsStatic)
578                 {
579                     _ilGen.Emit(OpCodes.Ldsfld, fieldInfo);
580                 }
581                 else
582                 {
583                     _ilGen.Emit(OpCodes.Ldfld, fieldInfo);
584                 }
585             }
586             else if (memberInfo is PropertyInfo property)
587             {
588                 memberType = property.PropertyType;
589                 MethodInfo? getMethod = property.GetMethod;
590                 if (getMethod == null)
591                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NoGetMethodForProperty, property.DeclaringType, property)));
592                 Call(getMethod);
593             }
594             else if (memberInfo is MethodInfo method)
595             {
596                 memberType = method.ReturnType;
597                 Call(method);
598             }
599             else
600                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CannotLoadMemberType, "Unknown", memberInfo.DeclaringType, memberInfo.Name)));
601
602             return memberType;
603         }
604
605         internal void StoreMember(MemberInfo memberInfo)
606         {
607             if (memberInfo is FieldInfo fieldInfo)
608             {
609                 if (fieldInfo.IsStatic)
610                 {
611                     _ilGen.Emit(OpCodes.Stsfld, fieldInfo);
612                 }
613                 else
614                 {
615                     _ilGen.Emit(OpCodes.Stfld, fieldInfo);
616                 }
617             }
618             else if (memberInfo is PropertyInfo property)
619             {
620                 MethodInfo? setMethod = property.SetMethod;
621                 if (setMethod == null)
622                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NoSetMethodForProperty, property.DeclaringType, property)));
623                 Call(setMethod);
624             }
625             else if (memberInfo is MethodInfo method)
626                 Call(method);
627             else
628                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CannotLoadMemberType, "Unknown")));
629         }
630
631         internal void LoadDefaultValue(Type type)
632         {
633             if (type.IsValueType)
634             {
635                 switch (Type.GetTypeCode(type))
636                 {
637                     case TypeCode.Boolean:
638                         Ldc(false);
639                         break;
640                     case TypeCode.Char:
641                     case TypeCode.SByte:
642                     case TypeCode.Byte:
643                     case TypeCode.Int16:
644                     case TypeCode.UInt16:
645                     case TypeCode.Int32:
646                     case TypeCode.UInt32:
647                         Ldc(0);
648                         break;
649                     case TypeCode.Int64:
650                     case TypeCode.UInt64:
651                         Ldc(0L);
652                         break;
653                     case TypeCode.Single:
654                         Ldc(0.0F);
655                         break;
656                     case TypeCode.Double:
657                         Ldc(0.0);
658                         break;
659                     case TypeCode.Decimal:
660                     case TypeCode.DateTime:
661                     default:
662                         LocalBuilder zero = DeclareLocal(type);
663                         LoadAddress(zero);
664                         InitObj(type);
665                         Load(zero);
666                         break;
667                 }
668             }
669             else
670                 Load(null);
671         }
672
673         internal void Load(object? obj)
674         {
675             if (obj == null)
676             {
677                 _ilGen.Emit(OpCodes.Ldnull);
678             }
679             else if (obj is ArgBuilder argBuilder)
680                 Ldarg(argBuilder);
681             else if (obj is LocalBuilder localBuilder)
682                 Ldloc(localBuilder);
683             else
684                 Ldc(obj);
685         }
686
687         internal void Store(object var)
688         {
689             if (var is ArgBuilder argBuilder)
690                 Starg(argBuilder);
691             else if (var is LocalBuilder localBuilder)
692                 Stloc(localBuilder);
693             else
694             {
695                 DiagnosticUtility.DebugAssert("Data can only be stored into ArgBuilder or LocalBuilder.");
696                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CanOnlyStoreIntoArgOrLocGot0, DataContract.GetClrTypeFullName(var.GetType()))));
697             }
698         }
699
700         internal void Dec(object var)
701         {
702             Load(var);
703             Load(1);
704             Subtract();
705             Store(var);
706         }
707
708         internal void LoadAddress(object obj)
709         {
710             if (obj is ArgBuilder argBuilder)
711                 LdargAddress(argBuilder);
712             else if (obj is LocalBuilder localBuilder)
713                 LdlocAddress(localBuilder);
714             else
715                 Load(obj);
716         }
717
718
719         internal void ConvertAddress(Type source, Type target)
720         {
721             InternalConvert(source, target, true);
722         }
723
724         internal void ConvertValue(Type source, Type target)
725         {
726             InternalConvert(source, target, false);
727         }
728
729
730         internal void Castclass(Type target)
731         {
732             _ilGen.Emit(OpCodes.Castclass, target);
733         }
734
735         internal void Box(Type type)
736         {
737             _ilGen.Emit(OpCodes.Box, type);
738         }
739
740         internal void Unbox(Type type)
741         {
742             _ilGen.Emit(OpCodes.Unbox, type);
743         }
744
745         private static OpCode GetLdindOpCode(TypeCode typeCode) =>
746             typeCode switch
747             {
748                 TypeCode.Boolean => OpCodes.Ldind_I1, // TypeCode.Boolean:
749                 TypeCode.Char => OpCodes.Ldind_I2,    // TypeCode.Char:
750                 TypeCode.SByte => OpCodes.Ldind_I1,   // TypeCode.SByte:
751                 TypeCode.Byte => OpCodes.Ldind_U1,    // TypeCode.Byte:
752                 TypeCode.Int16 => OpCodes.Ldind_I2,   // TypeCode.Int16:
753                 TypeCode.UInt16 => OpCodes.Ldind_U2,  // TypeCode.UInt16:
754                 TypeCode.Int32 => OpCodes.Ldind_I4,   // TypeCode.Int32:
755                 TypeCode.UInt32 => OpCodes.Ldind_U4,  // TypeCode.UInt32:
756                 TypeCode.Int64 => OpCodes.Ldind_I8,   // TypeCode.Int64:
757                 TypeCode.UInt64 => OpCodes.Ldind_I8,  // TypeCode.UInt64:
758                 TypeCode.Single => OpCodes.Ldind_R4,  // TypeCode.Single:
759                 TypeCode.Double => OpCodes.Ldind_R8,  // TypeCode.Double:
760                 TypeCode.String => OpCodes.Ldind_Ref, // TypeCode.String:
761                 _ => OpCodes.Nop,
762             };
763
764         internal void Ldobj(Type type)
765         {
766             OpCode opCode = GetLdindOpCode(Type.GetTypeCode(type));
767             if (!opCode.Equals(OpCodes.Nop))
768             {
769                 _ilGen.Emit(opCode);
770             }
771             else
772             {
773                 _ilGen.Emit(OpCodes.Ldobj, type);
774             }
775         }
776
777         internal void Stobj(Type type)
778         {
779             _ilGen.Emit(OpCodes.Stobj, type);
780         }
781
782
783         internal void Ceq()
784         {
785             _ilGen.Emit(OpCodes.Ceq);
786         }
787
788         internal void Throw()
789         {
790             _ilGen.Emit(OpCodes.Throw);
791         }
792
793         internal void Ldtoken(Type t)
794         {
795             _ilGen.Emit(OpCodes.Ldtoken, t);
796         }
797
798         internal void Ldc(object o)
799         {
800             Type valueType = o.GetType();
801             if (o is Type t)
802             {
803                 Ldtoken(t);
804                 Call(GetTypeFromHandle);
805             }
806             else if (valueType.IsEnum)
807             {
808                 Ldc(Convert.ChangeType(o, Enum.GetUnderlyingType(valueType), null));
809             }
810             else
811             {
812                 switch (Type.GetTypeCode(valueType))
813                 {
814                     case TypeCode.Boolean:
815                         Ldc((bool)o);
816                         break;
817                     case TypeCode.Char:
818                         DiagnosticUtility.DebugAssert("Char is not a valid schema primitive and should be treated as int in DataContract");
819                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.CharIsInvalidPrimitive));
820                     case TypeCode.SByte:
821                     case TypeCode.Byte:
822                     case TypeCode.Int16:
823                     case TypeCode.UInt16:
824                         Ldc(Convert.ToInt32(o, CultureInfo.InvariantCulture));
825                         break;
826                     case TypeCode.Int32:
827                         Ldc((int)o);
828                         break;
829                     case TypeCode.UInt32:
830                         Ldc((int)(uint)o);
831                         break;
832                     case TypeCode.UInt64:
833                         Ldc((long)(ulong)o);
834                         break;
835                     case TypeCode.Int64:
836                         Ldc((long)o);
837                         break;
838                     case TypeCode.Single:
839                         Ldc((float)o);
840                         break;
841                     case TypeCode.Double:
842                         Ldc((double)o);
843                         break;
844                     case TypeCode.String:
845                         Ldstr((string)o);
846                         break;
847                     case TypeCode.Object:
848                     case TypeCode.Decimal:
849                     case TypeCode.DateTime:
850                     case TypeCode.Empty:
851                     case TypeCode.DBNull:
852                     default:
853                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.UnknownConstantType, DataContract.GetClrTypeFullName(valueType))));
854                 }
855             }
856         }
857
858         internal void Ldc(bool boolVar)
859         {
860             if (boolVar)
861             {
862                 _ilGen.Emit(OpCodes.Ldc_I4_1);
863             }
864             else
865             {
866                 _ilGen.Emit(OpCodes.Ldc_I4_0);
867             }
868         }
869
870         internal void Ldc(int intVar)
871         {
872             _ilGen.Emit(OpCodes.Ldc_I4, intVar);
873         }
874
875         internal void Ldc(long l)
876         {
877             _ilGen.Emit(OpCodes.Ldc_I8, l);
878         }
879
880         internal void Ldc(float f)
881         {
882             _ilGen.Emit(OpCodes.Ldc_R4, f);
883         }
884
885         internal void Ldc(double d)
886         {
887             _ilGen.Emit(OpCodes.Ldc_R8, d);
888         }
889
890         internal void Ldstr(string strVar)
891         {
892             _ilGen.Emit(OpCodes.Ldstr, strVar);
893         }
894
895         internal void LdlocAddress(LocalBuilder localBuilder)
896         {
897             if (localBuilder.LocalType.IsValueType)
898                 Ldloca(localBuilder);
899             else
900                 Ldloc(localBuilder);
901         }
902
903         internal void Ldloc(LocalBuilder localBuilder)
904         {
905             _ilGen.Emit(OpCodes.Ldloc, localBuilder);
906         }
907
908         internal void Stloc(LocalBuilder local)
909         {
910             _ilGen.Emit(OpCodes.Stloc, local);
911         }
912
913         internal void Ldloca(LocalBuilder localBuilder)
914         {
915             _ilGen.Emit(OpCodes.Ldloca, localBuilder);
916         }
917
918         internal void LdargAddress(ArgBuilder argBuilder)
919         {
920             if (argBuilder.ArgType.IsValueType)
921                 Ldarga(argBuilder);
922             else
923                 Ldarg(argBuilder);
924         }
925
926         internal void Ldarg(ArgBuilder arg)
927         {
928             Ldarg(arg.Index);
929         }
930
931         internal void Starg(ArgBuilder arg)
932         {
933             Starg(arg.Index);
934         }
935
936         internal void Ldarg(int slot)
937         {
938             _ilGen.Emit(OpCodes.Ldarg, slot);
939         }
940
941         internal void Starg(int slot)
942         {
943             _ilGen.Emit(OpCodes.Starg, slot);
944         }
945
946         internal void Ldarga(ArgBuilder argBuilder)
947         {
948             Ldarga(argBuilder.Index);
949         }
950
951         internal void Ldarga(int slot)
952         {
953             _ilGen.Emit(OpCodes.Ldarga, slot);
954         }
955
956         internal void Ldlen()
957         {
958             _ilGen.Emit(OpCodes.Ldlen);
959             _ilGen.Emit(OpCodes.Conv_I4);
960         }
961
962         private static OpCode GetLdelemOpCode(TypeCode typeCode) =>
963             typeCode switch
964             {
965                 TypeCode.Object or TypeCode.DBNull => OpCodes.Ldelem_Ref, // TypeCode.Object:
966                 TypeCode.Boolean => OpCodes.Ldelem_I1, // TypeCode.Boolean:
967                 TypeCode.Char => OpCodes.Ldelem_I2,    // TypeCode.Char:
968                 TypeCode.SByte => OpCodes.Ldelem_I1,   // TypeCode.SByte:
969                 TypeCode.Byte => OpCodes.Ldelem_U1,    // TypeCode.Byte:
970                 TypeCode.Int16 => OpCodes.Ldelem_I2,   // TypeCode.Int16:
971                 TypeCode.UInt16 => OpCodes.Ldelem_U2,  // TypeCode.UInt16:
972                 TypeCode.Int32 => OpCodes.Ldelem_I4,   // TypeCode.Int32:
973                 TypeCode.UInt32 => OpCodes.Ldelem_U4,  // TypeCode.UInt32:
974                 TypeCode.Int64 => OpCodes.Ldelem_I8,   // TypeCode.Int64:
975                 TypeCode.UInt64 => OpCodes.Ldelem_I8,  // TypeCode.UInt64:
976                 TypeCode.Single => OpCodes.Ldelem_R4,  // TypeCode.Single:
977                 TypeCode.Double => OpCodes.Ldelem_R8,  // TypeCode.Double:
978                 TypeCode.String => OpCodes.Ldelem_Ref, // TypeCode.String:
979                 _ => OpCodes.Nop,
980             };
981
982         internal void Ldelem(Type arrayElementType)
983         {
984             if (arrayElementType.IsEnum)
985             {
986                 Ldelem(Enum.GetUnderlyingType(arrayElementType));
987             }
988             else
989             {
990                 OpCode opCode = GetLdelemOpCode(Type.GetTypeCode(arrayElementType));
991                 if (opCode.Equals(OpCodes.Nop))
992                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayTypeIsNotSupported_GeneratingCode, DataContract.GetClrTypeFullName(arrayElementType))));
993                 _ilGen.Emit(opCode);
994             }
995         }
996         internal void Ldelema(Type arrayElementType)
997         {
998             OpCode opCode = OpCodes.Ldelema;
999             _ilGen.Emit(opCode, arrayElementType);
1000         }
1001
1002         private static OpCode GetStelemOpCode(TypeCode typeCode) =>
1003             typeCode switch
1004             {
1005                 TypeCode.Object or TypeCode.DBNull => OpCodes.Stelem_Ref, // TypeCode.Object:
1006                 TypeCode.Boolean => OpCodes.Stelem_I1, // TypeCode.Boolean:
1007                 TypeCode.Char => OpCodes.Stelem_I2,    // TypeCode.Char:
1008                 TypeCode.SByte => OpCodes.Stelem_I1,   // TypeCode.SByte:
1009                 TypeCode.Byte => OpCodes.Stelem_I1,    // TypeCode.Byte:
1010                 TypeCode.Int16 => OpCodes.Stelem_I2,   // TypeCode.Int16:
1011                 TypeCode.UInt16 => OpCodes.Stelem_I2,  // TypeCode.UInt16:
1012                 TypeCode.Int32 => OpCodes.Stelem_I4,   // TypeCode.Int32:
1013                 TypeCode.UInt32 => OpCodes.Stelem_I4,  // TypeCode.UInt32:
1014                 TypeCode.Int64 => OpCodes.Stelem_I8,   // TypeCode.Int64:
1015                 TypeCode.UInt64 => OpCodes.Stelem_I8,  // TypeCode.UInt64:
1016                 TypeCode.Single => OpCodes.Stelem_R4,  // TypeCode.Single:
1017                 TypeCode.Double => OpCodes.Stelem_R8,  // TypeCode.Double:
1018                 TypeCode.String => OpCodes.Stelem_Ref, // TypeCode.String:
1019                 _ => OpCodes.Nop,
1020             };
1021
1022         internal void Stelem(Type arrayElementType)
1023         {
1024             if (arrayElementType.IsEnum)
1025                 Stelem(Enum.GetUnderlyingType(arrayElementType));
1026             else
1027             {
1028                 OpCode opCode = GetStelemOpCode(Type.GetTypeCode(arrayElementType));
1029                 if (opCode.Equals(OpCodes.Nop))
1030                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayTypeIsNotSupported_GeneratingCode, DataContract.GetClrTypeFullName(arrayElementType))));
1031                 _ilGen.Emit(opCode);
1032             }
1033         }
1034
1035         internal Label DefineLabel()
1036         {
1037             return _ilGen.DefineLabel();
1038         }
1039
1040         internal void MarkLabel(Label label)
1041         {
1042             _ilGen.MarkLabel(label);
1043         }
1044
1045         internal void Add()
1046         {
1047             _ilGen.Emit(OpCodes.Add);
1048         }
1049
1050         internal void Subtract()
1051         {
1052             _ilGen.Emit(OpCodes.Sub);
1053         }
1054
1055         internal void And()
1056         {
1057             _ilGen.Emit(OpCodes.And);
1058         }
1059         internal void Or()
1060         {
1061             _ilGen.Emit(OpCodes.Or);
1062         }
1063
1064         internal void Not()
1065         {
1066             _ilGen.Emit(OpCodes.Not);
1067         }
1068
1069         internal void Ret()
1070         {
1071             _ilGen.Emit(OpCodes.Ret);
1072         }
1073
1074         internal void Br(Label label)
1075         {
1076             _ilGen.Emit(OpCodes.Br, label);
1077         }
1078
1079         internal void Blt(Label label)
1080         {
1081             _ilGen.Emit(OpCodes.Blt, label);
1082         }
1083
1084         internal void Brfalse(Label label)
1085         {
1086             _ilGen.Emit(OpCodes.Brfalse, label);
1087         }
1088
1089         internal void Brtrue(Label label)
1090         {
1091             _ilGen.Emit(OpCodes.Brtrue, label);
1092         }
1093
1094         internal void Pop()
1095         {
1096             _ilGen.Emit(OpCodes.Pop);
1097         }
1098
1099         internal void Dup()
1100         {
1101             _ilGen.Emit(OpCodes.Dup);
1102         }
1103
1104         private void LoadThis(object? thisObj, MethodInfo methodInfo)
1105         {
1106             if (thisObj != null && !methodInfo.IsStatic)
1107             {
1108                 LoadAddress(thisObj);
1109                 ConvertAddress(GetVariableType(thisObj), methodInfo.DeclaringType!);
1110             }
1111         }
1112
1113         private void LoadParam(object? arg, int oneBasedArgIndex, MethodBase methodInfo)
1114         {
1115             Load(arg);
1116             if (arg != null)
1117                 ConvertValue(GetVariableType(arg), methodInfo.GetParameters()[oneBasedArgIndex - 1].ParameterType);
1118         }
1119
1120         private void InternalIf(bool negate)
1121         {
1122             IfState ifState = new IfState();
1123             ifState.EndIf = DefineLabel();
1124             ifState.ElseBegin = DefineLabel();
1125             if (negate)
1126                 Brtrue(ifState.ElseBegin);
1127             else
1128                 Brfalse(ifState.ElseBegin);
1129             _blockStack.Push(ifState);
1130         }
1131
1132         private static OpCode GetConvOpCode(TypeCode typeCode) =>
1133             typeCode switch
1134             {
1135                 TypeCode.Boolean => OpCodes.Conv_I1, // TypeCode.Boolean:
1136                 TypeCode.Char => OpCodes.Conv_I2,    // TypeCode.Char:
1137                 TypeCode.SByte => OpCodes.Conv_I1,   // TypeCode.SByte:
1138                 TypeCode.Byte => OpCodes.Conv_U1,    // TypeCode.Byte:
1139                 TypeCode.Int16 => OpCodes.Conv_I2,   // TypeCode.Int16:
1140                 TypeCode.UInt16 => OpCodes.Conv_U2,  // TypeCode.UInt16:
1141                 TypeCode.Int32 => OpCodes.Conv_I4,   // TypeCode.Int32:
1142                 TypeCode.UInt32 => OpCodes.Conv_U4,  // TypeCode.UInt32:
1143                 TypeCode.Int64 => OpCodes.Conv_I8,   // TypeCode.Int64:
1144                 TypeCode.UInt64 => OpCodes.Conv_I8,  // TypeCode.UInt64:
1145                 TypeCode.Single => OpCodes.Conv_R4,  // TypeCode.Single:
1146                 TypeCode.Double => OpCodes.Conv_R8,  // TypeCode.Double:
1147                 _ => OpCodes.Nop,
1148             };
1149
1150         private void InternalConvert(Type source, Type target, bool isAddress)
1151         {
1152             if (target == source)
1153                 return;
1154             if (target.IsValueType)
1155             {
1156                 if (source.IsValueType)
1157                 {
1158                     OpCode opCode = GetConvOpCode(Type.GetTypeCode(target));
1159                     if (opCode.Equals(OpCodes.Nop))
1160                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NoConversionPossibleTo, DataContract.GetClrTypeFullName(target))));
1161                     else
1162                     {
1163                         _ilGen.Emit(opCode);
1164                     }
1165                 }
1166                 else if (source.IsAssignableFrom(target))
1167                 {
1168                     Unbox(target);
1169                     if (!isAddress)
1170                         Ldobj(target);
1171                 }
1172                 else
1173                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IsNotAssignableFrom, DataContract.GetClrTypeFullName(target), DataContract.GetClrTypeFullName(source))));
1174             }
1175             else if (target.IsAssignableFrom(source))
1176             {
1177                 if (source.IsValueType)
1178                 {
1179                     if (isAddress)
1180                         Ldobj(source);
1181                     Box(source);
1182                 }
1183             }
1184             else if (source.IsAssignableFrom(target))
1185             {
1186                 Castclass(target);
1187             }
1188             else if (target.IsInterface || source.IsInterface)
1189             {
1190                 Castclass(target);
1191             }
1192             else
1193                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IsNotAssignableFrom, DataContract.GetClrTypeFullName(target), DataContract.GetClrTypeFullName(source))));
1194         }
1195
1196         private IfState PopIfState()
1197         {
1198             object stackTop = _blockStack.Pop();
1199             IfState? ifState = stackTop as IfState;
1200             if (ifState == null)
1201                 ThrowMismatchException(stackTop);
1202             return ifState;
1203         }
1204
1205         [DoesNotReturn]
1206         private static void ThrowMismatchException(object expected)
1207         {
1208             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ExpectingEnd, expected.ToString())));
1209         }
1210
1211         internal Label[] Switch(int labelCount)
1212         {
1213             SwitchState switchState = new SwitchState(DefineLabel(), DefineLabel());
1214             Label[] caseLabels = new Label[labelCount];
1215             for (int i = 0; i < caseLabels.Length; i++)
1216                 caseLabels[i] = DefineLabel();
1217
1218             _ilGen.Emit(OpCodes.Switch, caseLabels);
1219             Br(switchState.DefaultLabel);
1220             _blockStack.Push(switchState);
1221             return caseLabels;
1222         }
1223         internal void Case(Label caseLabel1)
1224         {
1225             MarkLabel(caseLabel1);
1226         }
1227
1228         internal void EndCase()
1229         {
1230             object stackTop = _blockStack.Peek();
1231             SwitchState? switchState = stackTop as SwitchState;
1232             if (switchState == null)
1233                 ThrowMismatchException(stackTop);
1234             Br(switchState.EndOfSwitchLabel);
1235         }
1236
1237         internal void EndSwitch()
1238         {
1239             object stackTop = _blockStack.Pop();
1240             SwitchState? switchState = stackTop as SwitchState;
1241             if (switchState == null)
1242                 ThrowMismatchException(stackTop);
1243             if (!switchState.DefaultDefined)
1244                 MarkLabel(switchState.DefaultLabel);
1245             MarkLabel(switchState.EndOfSwitchLabel);
1246         }
1247
1248         private static readonly MethodInfo s_stringLength = typeof(string).GetProperty("Length")!.GetMethod!;
1249         internal void ElseIfIsEmptyString(LocalBuilder strLocal)
1250         {
1251             IfState ifState = (IfState)_blockStack.Pop();
1252             Br(ifState.EndIf);
1253             MarkLabel(ifState.ElseBegin);
1254
1255             Load(strLocal);
1256             Call(s_stringLength);
1257             Load(0);
1258             ifState.ElseBegin = DefineLabel();
1259             _ilGen.Emit(GetBranchCode(Cmp.EqualTo), ifState.ElseBegin);
1260             _blockStack.Push(ifState);
1261         }
1262
1263         internal void IfNotIsEmptyString(LocalBuilder strLocal)
1264         {
1265             Load(strLocal);
1266             Call(s_stringLength);
1267             Load(0);
1268             If(Cmp.NotEqualTo);
1269         }
1270
1271         internal void BeginWhileCondition()
1272         {
1273             Label startWhile = DefineLabel();
1274             MarkLabel(startWhile);
1275             _blockStack.Push(startWhile);
1276         }
1277
1278         internal void BeginWhileBody(Cmp cmpOp)
1279         {
1280             Label startWhile = (Label)_blockStack.Pop();
1281             If(cmpOp);
1282             _blockStack.Push(startWhile);
1283         }
1284
1285         internal void EndWhile()
1286         {
1287             Label startWhile = (Label)_blockStack.Pop();
1288             Br(startWhile);
1289             EndIf();
1290         }
1291
1292         internal void CallStringFormat(string msg, params object[] values)
1293         {
1294             NewArray(typeof(object), values.Length);
1295             _stringFormatArray ??= DeclareLocal(typeof(object[]));
1296             Stloc(_stringFormatArray);
1297             for (int i = 0; i < values.Length; i++)
1298                 StoreArrayElement(_stringFormatArray, i, values[i]);
1299
1300             Load(msg);
1301             Load(_stringFormatArray);
1302             Call(StringFormat);
1303         }
1304
1305         internal void ToString(Type type)
1306         {
1307             if (type != Globals.TypeOfString)
1308             {
1309                 if (type.IsValueType)
1310                 {
1311                     Box(type);
1312                 }
1313                 Call(ObjectToString);
1314             }
1315         }
1316     }
1317
1318     internal sealed class ArgBuilder
1319     {
1320         internal int Index;
1321         internal Type ArgType;
1322         internal ArgBuilder(int index, Type argType)
1323         {
1324             Index = index;
1325             ArgType = argType;
1326         }
1327     }
1328
1329     internal sealed class ForState
1330     {
1331         private readonly LocalBuilder? _indexVar;
1332         private readonly Label _beginLabel;
1333         private readonly Label _testLabel;
1334         private Label _endLabel;
1335         private bool _requiresEndLabel;
1336         private readonly object? _end;
1337
1338         internal ForState(LocalBuilder? indexVar, Label beginLabel, Label testLabel, object? end)
1339         {
1340             _indexVar = indexVar;
1341             _beginLabel = beginLabel;
1342             _testLabel = testLabel;
1343             _end = end;
1344         }
1345
1346         internal LocalBuilder? Index
1347         {
1348             get
1349             {
1350                 return _indexVar;
1351             }
1352         }
1353
1354         internal Label BeginLabel
1355         {
1356             get
1357             {
1358                 return _beginLabel;
1359             }
1360         }
1361
1362         internal Label TestLabel
1363         {
1364             get
1365             {
1366                 return _testLabel;
1367             }
1368         }
1369
1370         internal Label EndLabel
1371         {
1372             get
1373             {
1374                 return _endLabel;
1375             }
1376             set
1377             {
1378                 _endLabel = value;
1379             }
1380         }
1381
1382         internal bool RequiresEndLabel
1383         {
1384             get
1385             {
1386                 return _requiresEndLabel;
1387             }
1388             set
1389             {
1390                 _requiresEndLabel = value;
1391             }
1392         }
1393
1394         internal object? End
1395         {
1396             get
1397             {
1398                 return _end;
1399             }
1400         }
1401     }
1402
1403     internal enum Cmp
1404     {
1405         LessThan,
1406         EqualTo,
1407         LessThanOrEqualTo,
1408         GreaterThan,
1409         NotEqualTo,
1410         GreaterThanOrEqualTo
1411     }
1412
1413     internal sealed class IfState
1414     {
1415         private Label _elseBegin;
1416         private Label _endIf;
1417
1418         internal Label EndIf
1419         {
1420             get
1421             {
1422                 return _endIf;
1423             }
1424             set
1425             {
1426                 _endIf = value;
1427             }
1428         }
1429
1430         internal Label ElseBegin
1431         {
1432             get
1433             {
1434                 return _elseBegin;
1435             }
1436             set
1437             {
1438                 _elseBegin = value;
1439             }
1440         }
1441     }
1442
1443
1444     internal sealed class SwitchState
1445     {
1446         private readonly Label _defaultLabel;
1447         private readonly Label _endOfSwitchLabel;
1448         private bool _defaultDefined;
1449         internal SwitchState(Label defaultLabel, Label endOfSwitchLabel)
1450         {
1451             _defaultLabel = defaultLabel;
1452             _endOfSwitchLabel = endOfSwitchLabel;
1453             _defaultDefined = false;
1454         }
1455         internal Label DefaultLabel
1456         {
1457             get
1458             {
1459                 return _defaultLabel;
1460             }
1461         }
1462
1463         internal Label EndOfSwitchLabel
1464         {
1465             get
1466             {
1467                 return _endOfSwitchLabel;
1468             }
1469         }
1470         internal bool DefaultDefined
1471         {
1472             get
1473             {
1474                 return _defaultDefined;
1475             }
1476             set
1477             {
1478                 _defaultDefined = value;
1479             }
1480         }
1481     }
1482 }