1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
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;
13 namespace System.Runtime.Serialization
15 internal sealed class CodeGenerator
17 private static MethodInfo? s_getTypeFromHandle;
18 private static MethodInfo GetTypeFromHandle
22 if (s_getTypeFromHandle == null)
24 s_getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle");
25 Debug.Assert(s_getTypeFromHandle != null);
27 return s_getTypeFromHandle;
31 private static MethodInfo? s_objectEquals;
32 private static MethodInfo ObjectEquals
36 if (s_objectEquals == null)
38 s_objectEquals = typeof(object).GetMethod("Equals", BindingFlags.Public | BindingFlags.Static);
39 Debug.Assert(s_objectEquals != null);
41 return s_objectEquals;
45 private static MethodInfo? s_arraySetValue;
46 private static MethodInfo ArraySetValue
50 if (s_arraySetValue == null)
52 s_arraySetValue = typeof(Array).GetMethod("SetValue", new Type[] { typeof(object), typeof(int) });
53 Debug.Assert(s_arraySetValue != null);
55 return s_arraySetValue;
59 private static MethodInfo? s_objectToString;
60 private static MethodInfo ObjectToString
64 if (s_objectToString == null)
66 s_objectToString = typeof(object).GetMethod("ToString", Type.EmptyTypes);
67 Debug.Assert(s_objectToString != null);
69 return s_objectToString;
73 private static MethodInfo? s_stringFormat;
74 private static MethodInfo StringFormat
78 if (s_stringFormat == null)
80 s_stringFormat = typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object[]) });
81 Debug.Assert(s_stringFormat != null);
83 return s_stringFormat;
87 [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
88 Justification = "The trimmer will never remove the Invoke method from delegates.")]
89 internal static MethodInfo GetInvokeMethod(Type delegateType)
91 Debug.Assert(typeof(Delegate).IsAssignableFrom(delegateType));
92 return delegateType.GetMethod("Invoke")!;
95 private Type _delegateType = null!; // initialized in BeginMethod
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
100 private DynamicMethod _dynamicMethod = null!; // initialized in BeginMethod
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;
107 private LocalBuilder? _stringFormatArray;
109 internal CodeGenerator() { }
111 internal void BeginMethod(DynamicMethod dynamicMethod, Type delegateType, Type[] argTypes)
113 _dynamicMethod = dynamicMethod;
114 _ilGen = _dynamicMethod.GetILGenerator();
115 _delegateType = delegateType;
117 InitILGeneration(argTypes);
120 [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
121 internal void BeginMethod(string methodName, Type delegateType, bool allowPrivateMemberAccess)
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;
132 [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
133 private void BeginMethod(Type returnType, string methodName, Type[] argTypes, bool allowPrivateMemberAccess)
135 _dynamicMethod = new DynamicMethod(methodName, returnType, argTypes, SerializationModule, allowPrivateMemberAccess);
137 _ilGen = _dynamicMethod.GetILGenerator();
139 InitILGeneration(argTypes);
142 private void InitILGeneration(Type[] argTypes)
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]));
151 internal Delegate EndMethod()
153 MarkLabel(_methodEndLabel);
157 retVal = _dynamicMethod.CreateDelegate(_delegateType);
158 _dynamicMethod = null!;
159 _delegateType = null!;
167 internal MethodInfo CurrentMethod
171 return _dynamicMethod;
175 internal ArgBuilder GetArg(int index)
177 return _argList[index];
180 internal static Type GetVariableType(object var)
182 if (var is ArgBuilder argBuilder)
183 return argBuilder.ArgType;
184 else if (var is LocalBuilder localBuilder)
185 return localBuilder.LocalType;
187 return var.GetType();
190 internal LocalBuilder DeclareLocal(Type type, object initialValue)
192 LocalBuilder local = DeclareLocal(type);
198 internal LocalBuilder DeclareLocal(Type type)
200 return DeclareLocal(type, false);
203 internal LocalBuilder DeclareLocal(Type type, bool isPinned)
205 return _ilGen.DeclareLocal(type, isPinned);
208 internal void Set(LocalBuilder local, object value)
214 internal object For(LocalBuilder? local, object? start, object? end)
216 ForState forState = new ForState(local, DefineLabel(), DefineLabel(), end);
217 if (forState.Index != null)
220 Stloc(forState.Index);
221 Br(forState.TestLabel);
223 MarkLabel(forState.BeginLabel);
224 _blockStack.Push(forState);
228 internal void EndFor()
230 object stackTop = _blockStack.Pop();
231 ForState? forState = stackTop as ForState;
232 if (forState == null)
233 ThrowMismatchException(stackTop);
235 if (forState.Index != null)
237 Ldloc(forState.Index);
240 Stloc(forState.Index);
241 MarkLabel(forState.TestLabel);
242 Ldloc(forState.Index);
244 if (GetVariableType(forState.End!).IsArray)
246 Blt(forState.BeginLabel);
249 Br(forState.BeginLabel);
250 if (forState.RequiresEndLabel)
251 MarkLabel(forState.EndLabel);
254 internal void Break(object forState)
256 InternalBreakFor(forState, OpCodes.Br);
259 internal void IfFalseBreak(object forState)
261 InternalBreakFor(forState, OpCodes.Brfalse);
264 internal void InternalBreakFor(object userForState, OpCode branchInstruction)
266 foreach (object block in _blockStack)
268 if (block == userForState && block is ForState forState)
270 if (!forState.RequiresEndLabel)
272 forState.EndLabel = DefineLabel();
273 forState.RequiresEndLabel = true;
276 _ilGen.Emit(branchInstruction, forState.EndLabel);
282 internal void ForEach(LocalBuilder local, Type elementType,
283 LocalBuilder enumerator, MethodInfo getCurrentMethod)
285 ForState forState = new ForState(local, DefineLabel(), DefineLabel(), enumerator);
287 Br(forState.TestLabel);
288 MarkLabel(forState.BeginLabel);
290 Call(enumerator, getCurrentMethod);
292 ConvertValue(elementType, GetVariableType(local));
294 _blockStack.Push(forState);
297 internal void EndForEach(MethodInfo moveNextMethod)
299 object stackTop = _blockStack.Pop();
300 ForState? forState = stackTop as ForState;
301 if (forState == null)
302 ThrowMismatchException(stackTop);
304 MarkLabel(forState.TestLabel);
306 object? enumerator = forState.End;
307 Call(enumerator, moveNextMethod);
310 Brtrue(forState.BeginLabel);
311 if (forState.RequiresEndLabel)
312 MarkLabel(forState.EndLabel);
315 internal void IfNotDefaultValue(object value)
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)
322 LoadDefaultValue(type);
323 ConvertValue(type, Globals.TypeOfObject);
325 ConvertValue(type, Globals.TypeOfObject);
331 LoadDefaultValue(type);
342 internal void IfNot()
347 private static OpCode GetBranchCode(Cmp cmp)
354 return OpCodes.Bne_Un;
355 case Cmp.LessThanOrEqualTo:
357 case Cmp.GreaterThan:
362 DiagnosticUtility.DebugAssert(cmp == Cmp.GreaterThanOrEqualTo, "Unexpected cmp");
367 internal void If(Cmp cmpOp)
369 IfState ifState = new IfState();
370 ifState.EndIf = DefineLabel();
371 ifState.ElseBegin = DefineLabel();
372 _ilGen.Emit(GetBranchCode(cmpOp), ifState.ElseBegin);
373 _blockStack.Push(ifState);
377 internal void If(object value1, Cmp cmpOp, object? value2)
385 IfState ifState = PopIfState();
387 MarkLabel(ifState.ElseBegin);
389 ifState.ElseBegin = ifState.EndIf;
390 _blockStack.Push(ifState);
393 internal void ElseIf(object value1, Cmp cmpOp, object value2)
395 IfState ifState = (IfState)_blockStack.Pop();
397 MarkLabel(ifState.ElseBegin);
401 ifState.ElseBegin = DefineLabel();
403 _ilGen.Emit(GetBranchCode(cmpOp), ifState.ElseBegin);
404 _blockStack.Push(ifState);
408 internal void EndIf()
410 IfState ifState = PopIfState();
411 if (!ifState.ElseBegin.Equals(ifState.EndIf))
412 MarkLabel(ifState.ElseBegin);
413 MarkLabel(ifState.EndIf);
416 internal static void VerifyParameterCount(MethodInfo methodInfo, int expectedCount)
418 if (methodInfo.GetParameters().Length != expectedCount)
419 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ParameterCountMismatch, methodInfo.Name, methodInfo.GetParameters().Length, expectedCount)));
422 internal void Call(object? thisObj, MethodInfo methodInfo)
424 VerifyParameterCount(methodInfo, 0);
425 LoadThis(thisObj, methodInfo);
429 internal void Call(object? thisObj, MethodInfo methodInfo, object? param1)
431 VerifyParameterCount(methodInfo, 1);
432 LoadThis(thisObj, methodInfo);
433 LoadParam(param1, 1, methodInfo);
437 internal void Call(object? thisObj, MethodInfo methodInfo, object? param1, object? param2)
439 VerifyParameterCount(methodInfo, 2);
440 LoadThis(thisObj, methodInfo);
441 LoadParam(param1, 1, methodInfo);
442 LoadParam(param2, 2, methodInfo);
446 internal void Call(object? thisObj, MethodInfo methodInfo, object? param1, object? param2, object? param3)
448 VerifyParameterCount(methodInfo, 3);
449 LoadThis(thisObj, methodInfo);
450 LoadParam(param1, 1, methodInfo);
451 LoadParam(param2, 2, methodInfo);
452 LoadParam(param3, 3, methodInfo);
456 internal void Call(object? thisObj, MethodInfo methodInfo, object? param1, object? param2, object? param3, object? param4)
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);
467 internal void Call(object? thisObj, MethodInfo methodInfo, object? param1, object? param2, object? param3, object? param4, object? param5)
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);
479 internal void Call(object? thisObj, MethodInfo methodInfo, object? param1, object? param2, object? param3, object? param4, object? param5, object? param6)
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);
492 internal void Call(MethodInfo methodInfo)
494 if (methodInfo.IsVirtual && !methodInfo.DeclaringType!.IsValueType)
496 _ilGen.Emit(OpCodes.Callvirt, methodInfo);
498 else if (methodInfo.IsStatic)
500 _ilGen.Emit(OpCodes.Call, methodInfo);
504 _ilGen.Emit(OpCodes.Call, methodInfo);
508 internal void Call(ConstructorInfo ctor)
510 _ilGen.Emit(OpCodes.Call, ctor);
513 internal void New(ConstructorInfo constructorInfo)
515 _ilGen.Emit(OpCodes.Newobj, constructorInfo);
518 internal void InitObj(Type valueType)
520 _ilGen.Emit(OpCodes.Initobj, valueType);
523 internal void NewArray(Type elementType, object len)
526 _ilGen.Emit(OpCodes.Newarr, elementType);
529 internal void LoadArrayElement(object obj, object? arrayIndex)
531 Type objType = GetVariableType(obj).GetElementType()!;
534 if (IsStruct(objType))
543 internal void StoreArrayElement(object obj, object arrayIndex, object value)
545 Type arrayType = GetVariableType(obj);
546 if (arrayType == Globals.TypeOfArray)
548 Call(obj, ArraySetValue, value, arrayIndex);
552 Type objType = arrayType.GetElementType()!;
555 if (IsStruct(objType))
558 ConvertValue(GetVariableType(value), objType);
559 if (IsStruct(objType))
566 private static bool IsStruct(Type objType)
568 return objType.IsValueType && !objType.IsPrimitive;
571 internal Type LoadMember(MemberInfo memberInfo)
574 if (memberInfo is FieldInfo fieldInfo)
576 memberType = fieldInfo.FieldType;
577 if (fieldInfo.IsStatic)
579 _ilGen.Emit(OpCodes.Ldsfld, fieldInfo);
583 _ilGen.Emit(OpCodes.Ldfld, fieldInfo);
586 else if (memberInfo is PropertyInfo property)
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)));
594 else if (memberInfo is MethodInfo method)
596 memberType = method.ReturnType;
600 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CannotLoadMemberType, "Unknown", memberInfo.DeclaringType, memberInfo.Name)));
605 internal void StoreMember(MemberInfo memberInfo)
607 if (memberInfo is FieldInfo fieldInfo)
609 if (fieldInfo.IsStatic)
611 _ilGen.Emit(OpCodes.Stsfld, fieldInfo);
615 _ilGen.Emit(OpCodes.Stfld, fieldInfo);
618 else if (memberInfo is PropertyInfo property)
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)));
625 else if (memberInfo is MethodInfo method)
628 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CannotLoadMemberType, "Unknown")));
631 internal void LoadDefaultValue(Type type)
633 if (type.IsValueType)
635 switch (Type.GetTypeCode(type))
637 case TypeCode.Boolean:
644 case TypeCode.UInt16:
646 case TypeCode.UInt32:
650 case TypeCode.UInt64:
653 case TypeCode.Single:
656 case TypeCode.Double:
659 case TypeCode.Decimal:
660 case TypeCode.DateTime:
662 LocalBuilder zero = DeclareLocal(type);
673 internal void Load(object? obj)
677 _ilGen.Emit(OpCodes.Ldnull);
679 else if (obj is ArgBuilder argBuilder)
681 else if (obj is LocalBuilder localBuilder)
687 internal void Store(object var)
689 if (var is ArgBuilder argBuilder)
691 else if (var is LocalBuilder localBuilder)
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()))));
700 internal void Dec(object var)
708 internal void LoadAddress(object obj)
710 if (obj is ArgBuilder argBuilder)
711 LdargAddress(argBuilder);
712 else if (obj is LocalBuilder localBuilder)
713 LdlocAddress(localBuilder);
719 internal void ConvertAddress(Type source, Type target)
721 InternalConvert(source, target, true);
724 internal void ConvertValue(Type source, Type target)
726 InternalConvert(source, target, false);
730 internal void Castclass(Type target)
732 _ilGen.Emit(OpCodes.Castclass, target);
735 internal void Box(Type type)
737 _ilGen.Emit(OpCodes.Box, type);
740 internal void Unbox(Type type)
742 _ilGen.Emit(OpCodes.Unbox, type);
745 private static OpCode GetLdindOpCode(TypeCode typeCode) =>
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:
764 internal void Ldobj(Type type)
766 OpCode opCode = GetLdindOpCode(Type.GetTypeCode(type));
767 if (!opCode.Equals(OpCodes.Nop))
773 _ilGen.Emit(OpCodes.Ldobj, type);
777 internal void Stobj(Type type)
779 _ilGen.Emit(OpCodes.Stobj, type);
785 _ilGen.Emit(OpCodes.Ceq);
788 internal void Throw()
790 _ilGen.Emit(OpCodes.Throw);
793 internal void Ldtoken(Type t)
795 _ilGen.Emit(OpCodes.Ldtoken, t);
798 internal void Ldc(object o)
800 Type valueType = o.GetType();
804 Call(GetTypeFromHandle);
806 else if (valueType.IsEnum)
808 Ldc(Convert.ChangeType(o, Enum.GetUnderlyingType(valueType), null));
812 switch (Type.GetTypeCode(valueType))
814 case TypeCode.Boolean:
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));
823 case TypeCode.UInt16:
824 Ldc(Convert.ToInt32(o, CultureInfo.InvariantCulture));
829 case TypeCode.UInt32:
832 case TypeCode.UInt64:
838 case TypeCode.Single:
841 case TypeCode.Double:
844 case TypeCode.String:
847 case TypeCode.Object:
848 case TypeCode.Decimal:
849 case TypeCode.DateTime:
851 case TypeCode.DBNull:
853 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.UnknownConstantType, DataContract.GetClrTypeFullName(valueType))));
858 internal void Ldc(bool boolVar)
862 _ilGen.Emit(OpCodes.Ldc_I4_1);
866 _ilGen.Emit(OpCodes.Ldc_I4_0);
870 internal void Ldc(int intVar)
872 _ilGen.Emit(OpCodes.Ldc_I4, intVar);
875 internal void Ldc(long l)
877 _ilGen.Emit(OpCodes.Ldc_I8, l);
880 internal void Ldc(float f)
882 _ilGen.Emit(OpCodes.Ldc_R4, f);
885 internal void Ldc(double d)
887 _ilGen.Emit(OpCodes.Ldc_R8, d);
890 internal void Ldstr(string strVar)
892 _ilGen.Emit(OpCodes.Ldstr, strVar);
895 internal void LdlocAddress(LocalBuilder localBuilder)
897 if (localBuilder.LocalType.IsValueType)
898 Ldloca(localBuilder);
903 internal void Ldloc(LocalBuilder localBuilder)
905 _ilGen.Emit(OpCodes.Ldloc, localBuilder);
908 internal void Stloc(LocalBuilder local)
910 _ilGen.Emit(OpCodes.Stloc, local);
913 internal void Ldloca(LocalBuilder localBuilder)
915 _ilGen.Emit(OpCodes.Ldloca, localBuilder);
918 internal void LdargAddress(ArgBuilder argBuilder)
920 if (argBuilder.ArgType.IsValueType)
926 internal void Ldarg(ArgBuilder arg)
931 internal void Starg(ArgBuilder arg)
936 internal void Ldarg(int slot)
938 _ilGen.Emit(OpCodes.Ldarg, slot);
941 internal void Starg(int slot)
943 _ilGen.Emit(OpCodes.Starg, slot);
946 internal void Ldarga(ArgBuilder argBuilder)
948 Ldarga(argBuilder.Index);
951 internal void Ldarga(int slot)
953 _ilGen.Emit(OpCodes.Ldarga, slot);
956 internal void Ldlen()
958 _ilGen.Emit(OpCodes.Ldlen);
959 _ilGen.Emit(OpCodes.Conv_I4);
962 private static OpCode GetLdelemOpCode(TypeCode typeCode) =>
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:
982 internal void Ldelem(Type arrayElementType)
984 if (arrayElementType.IsEnum)
986 Ldelem(Enum.GetUnderlyingType(arrayElementType));
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))));
996 internal void Ldelema(Type arrayElementType)
998 OpCode opCode = OpCodes.Ldelema;
999 _ilGen.Emit(opCode, arrayElementType);
1002 private static OpCode GetStelemOpCode(TypeCode typeCode) =>
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:
1022 internal void Stelem(Type arrayElementType)
1024 if (arrayElementType.IsEnum)
1025 Stelem(Enum.GetUnderlyingType(arrayElementType));
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);
1035 internal Label DefineLabel()
1037 return _ilGen.DefineLabel();
1040 internal void MarkLabel(Label label)
1042 _ilGen.MarkLabel(label);
1047 _ilGen.Emit(OpCodes.Add);
1050 internal void Subtract()
1052 _ilGen.Emit(OpCodes.Sub);
1057 _ilGen.Emit(OpCodes.And);
1061 _ilGen.Emit(OpCodes.Or);
1066 _ilGen.Emit(OpCodes.Not);
1071 _ilGen.Emit(OpCodes.Ret);
1074 internal void Br(Label label)
1076 _ilGen.Emit(OpCodes.Br, label);
1079 internal void Blt(Label label)
1081 _ilGen.Emit(OpCodes.Blt, label);
1084 internal void Brfalse(Label label)
1086 _ilGen.Emit(OpCodes.Brfalse, label);
1089 internal void Brtrue(Label label)
1091 _ilGen.Emit(OpCodes.Brtrue, label);
1096 _ilGen.Emit(OpCodes.Pop);
1101 _ilGen.Emit(OpCodes.Dup);
1104 private void LoadThis(object? thisObj, MethodInfo methodInfo)
1106 if (thisObj != null && !methodInfo.IsStatic)
1108 LoadAddress(thisObj);
1109 ConvertAddress(GetVariableType(thisObj), methodInfo.DeclaringType!);
1113 private void LoadParam(object? arg, int oneBasedArgIndex, MethodBase methodInfo)
1117 ConvertValue(GetVariableType(arg), methodInfo.GetParameters()[oneBasedArgIndex - 1].ParameterType);
1120 private void InternalIf(bool negate)
1122 IfState ifState = new IfState();
1123 ifState.EndIf = DefineLabel();
1124 ifState.ElseBegin = DefineLabel();
1126 Brtrue(ifState.ElseBegin);
1128 Brfalse(ifState.ElseBegin);
1129 _blockStack.Push(ifState);
1132 private static OpCode GetConvOpCode(TypeCode typeCode) =>
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:
1150 private void InternalConvert(Type source, Type target, bool isAddress)
1152 if (target == source)
1154 if (target.IsValueType)
1156 if (source.IsValueType)
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))));
1163 _ilGen.Emit(opCode);
1166 else if (source.IsAssignableFrom(target))
1173 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IsNotAssignableFrom, DataContract.GetClrTypeFullName(target), DataContract.GetClrTypeFullName(source))));
1175 else if (target.IsAssignableFrom(source))
1177 if (source.IsValueType)
1184 else if (source.IsAssignableFrom(target))
1188 else if (target.IsInterface || source.IsInterface)
1193 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IsNotAssignableFrom, DataContract.GetClrTypeFullName(target), DataContract.GetClrTypeFullName(source))));
1196 private IfState PopIfState()
1198 object stackTop = _blockStack.Pop();
1199 IfState? ifState = stackTop as IfState;
1200 if (ifState == null)
1201 ThrowMismatchException(stackTop);
1206 private static void ThrowMismatchException(object expected)
1208 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ExpectingEnd, expected.ToString())));
1211 internal Label[] Switch(int labelCount)
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();
1218 _ilGen.Emit(OpCodes.Switch, caseLabels);
1219 Br(switchState.DefaultLabel);
1220 _blockStack.Push(switchState);
1223 internal void Case(Label caseLabel1)
1225 MarkLabel(caseLabel1);
1228 internal void EndCase()
1230 object stackTop = _blockStack.Peek();
1231 SwitchState? switchState = stackTop as SwitchState;
1232 if (switchState == null)
1233 ThrowMismatchException(stackTop);
1234 Br(switchState.EndOfSwitchLabel);
1237 internal void EndSwitch()
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);
1248 private static readonly MethodInfo s_stringLength = typeof(string).GetProperty("Length")!.GetMethod!;
1249 internal void ElseIfIsEmptyString(LocalBuilder strLocal)
1251 IfState ifState = (IfState)_blockStack.Pop();
1253 MarkLabel(ifState.ElseBegin);
1256 Call(s_stringLength);
1258 ifState.ElseBegin = DefineLabel();
1259 _ilGen.Emit(GetBranchCode(Cmp.EqualTo), ifState.ElseBegin);
1260 _blockStack.Push(ifState);
1263 internal void IfNotIsEmptyString(LocalBuilder strLocal)
1266 Call(s_stringLength);
1271 internal void BeginWhileCondition()
1273 Label startWhile = DefineLabel();
1274 MarkLabel(startWhile);
1275 _blockStack.Push(startWhile);
1278 internal void BeginWhileBody(Cmp cmpOp)
1280 Label startWhile = (Label)_blockStack.Pop();
1282 _blockStack.Push(startWhile);
1285 internal void EndWhile()
1287 Label startWhile = (Label)_blockStack.Pop();
1292 internal void CallStringFormat(string msg, params object[] values)
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]);
1301 Load(_stringFormatArray);
1305 internal void ToString(Type type)
1307 if (type != Globals.TypeOfString)
1309 if (type.IsValueType)
1313 Call(ObjectToString);
1318 internal sealed class ArgBuilder
1321 internal Type ArgType;
1322 internal ArgBuilder(int index, Type argType)
1329 internal sealed class ForState
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;
1338 internal ForState(LocalBuilder? indexVar, Label beginLabel, Label testLabel, object? end)
1340 _indexVar = indexVar;
1341 _beginLabel = beginLabel;
1342 _testLabel = testLabel;
1346 internal LocalBuilder? Index
1354 internal Label BeginLabel
1362 internal Label TestLabel
1370 internal Label EndLabel
1382 internal bool RequiresEndLabel
1386 return _requiresEndLabel;
1390 _requiresEndLabel = value;
1394 internal object? End
1410 GreaterThanOrEqualTo
1413 internal sealed class IfState
1415 private Label _elseBegin;
1416 private Label _endIf;
1418 internal Label EndIf
1430 internal Label ElseBegin
1444 internal sealed class SwitchState
1446 private readonly Label _defaultLabel;
1447 private readonly Label _endOfSwitchLabel;
1448 private bool _defaultDefined;
1449 internal SwitchState(Label defaultLabel, Label endOfSwitchLabel)
1451 _defaultLabel = defaultLabel;
1452 _endOfSwitchLabel = endOfSwitchLabel;
1453 _defaultDefined = false;
1455 internal Label DefaultLabel
1459 return _defaultLabel;
1463 internal Label EndOfSwitchLabel
1467 return _endOfSwitchLabel;
1470 internal bool DefaultDefined
1474 return _defaultDefined;
1478 _defaultDefined = value;