//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // [....] //------------------------------------------------------------------------------ using System; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; namespace System.Xml.Serialization { using System; using System.Collections; using System.Collections.Generic; using System.Configuration; using System.Globalization; using System.Xml; using System.Xml.Serialization.Configuration; using System.Reflection; using System.Reflection.Emit; using System.IO; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; internal class CodeGenerator { [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Method does validation only without any user input")] internal static bool IsValidLanguageIndependentIdentifier(string ident) { return System.CodeDom.Compiler.CodeGenerator.IsValidLanguageIndependentIdentifier(ident); } [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Method does validation only without any user input")] internal static void ValidateIdentifiers(System.CodeDom.CodeObject e) { System.CodeDom.Compiler.CodeGenerator.ValidateIdentifiers(e); } internal static BindingFlags InstancePublicBindingFlags = BindingFlags.Instance | BindingFlags.Public; internal static BindingFlags InstanceBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; internal static BindingFlags StaticBindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; internal static MethodAttributes PublicMethodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig; internal static MethodAttributes PublicOverrideMethodAttributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig; internal static MethodAttributes ProtectedOverrideMethodAttributes = MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig; internal static MethodAttributes PrivateMethodAttributes = MethodAttributes.Private | MethodAttributes.HideBySig; internal static Type[] EmptyTypeArray = new Type[] { }; internal static string[] EmptyStringArray = new string[] { }; TypeBuilder typeBuilder; MethodBuilder methodBuilder; ILGenerator ilGen; Dictionary argList; LocalScope currentScope; // Stores a queue of free locals available in the context of the method, keyed by // type and name of the local Dictionary, Queue> freeLocals; Stack blockStack; Label methodEndLabel; internal CodeGenerator(TypeBuilder typeBuilder) { System.Diagnostics.Debug.Assert(typeBuilder != null); this.typeBuilder = typeBuilder; } internal static bool IsNullableGenericType(Type type) { return type.Name == "Nullable`1"; } internal static void AssertHasInterface(Type type, Type iType) { #if DEBUG Debug.Assert(iType.IsInterface); foreach (Type iFace in type.GetInterfaces()) { if (iFace == iType) return; } Debug.Assert(false); #endif } internal void BeginMethod(Type returnType, string methodName, Type[] argTypes, string[] argNames, MethodAttributes methodAttributes) { this.methodBuilder = typeBuilder.DefineMethod(methodName, methodAttributes, returnType, argTypes); this.ilGen = methodBuilder.GetILGenerator(); InitILGeneration(argTypes, argNames, (methodBuilder.Attributes & MethodAttributes.Static) == MethodAttributes.Static); } internal void BeginMethod(Type returnType, MethodBuilderInfo methodBuilderInfo, Type[] argTypes, string[] argNames, MethodAttributes methodAttributes) { #if DEBUG methodBuilderInfo.Validate(returnType, argTypes, methodAttributes); #endif this.methodBuilder = methodBuilderInfo.MethodBuilder; this.ilGen = methodBuilder.GetILGenerator(); InitILGeneration(argTypes, argNames, (methodBuilder.Attributes & MethodAttributes.Static) == MethodAttributes.Static); } void InitILGeneration(Type[] argTypes, string[] argNames, bool isStatic) { this.methodEndLabel = ilGen.DefineLabel(); this.retLabel = ilGen.DefineLabel(); this.blockStack = new Stack(); this.whileStack = new Stack(); this.currentScope = new LocalScope(); this.freeLocals = new Dictionary, Queue>(); this.argList = new Dictionary(); // this ptr is arg 0 for non static, assuming ref type (not value type) if (!isStatic) argList.Add("this", new ArgBuilder("this", 0, this.typeBuilder.BaseType)); for (int i = 0; i < argTypes.Length; i++) { ArgBuilder arg = new ArgBuilder(argNames[i], argList.Count, argTypes[i]); argList.Add(arg.Name, arg); this.methodBuilder.DefineParameter(arg.Index, ParameterAttributes.None, arg.Name); } } internal MethodBuilder EndMethod() { MarkLabel(methodEndLabel); Ret(); MethodBuilder retVal = null; retVal = methodBuilder; methodBuilder = null; ilGen = null; freeLocals = null; blockStack = null; whileStack = null; argList = null; currentScope = null; retLocal = null; return retVal; } internal MethodBuilder MethodBuilder { get { return this.methodBuilder; } } internal static Exception NotSupported(string msg) { System.Diagnostics.Debug.Assert(false, msg); return new NotSupportedException(msg); } internal ArgBuilder GetArg(string name) { System.Diagnostics.Debug.Assert(argList != null && argList.ContainsKey(name)); return (ArgBuilder)argList[name]; } internal LocalBuilder GetLocal(string name) { System.Diagnostics.Debug.Assert(currentScope != null && currentScope.ContainsKey(name)); return currentScope[name]; } internal LocalBuilder retLocal; internal Label retLabel; internal LocalBuilder ReturnLocal { get { if (retLocal == null) retLocal = DeclareLocal(this.methodBuilder.ReturnType, "_ret"); return retLocal; } } internal Label ReturnLabel { get { return retLabel; } } Dictionary TmpLocals = new Dictionary(); internal LocalBuilder GetTempLocal(Type type) { LocalBuilder localTmp; if (!TmpLocals.TryGetValue(type, out localTmp)) { localTmp = DeclareLocal(type, "_tmp" + TmpLocals.Count); TmpLocals.Add(type, localTmp); } return localTmp; } internal Type GetVariableType(object var) { if (var is ArgBuilder) return ((ArgBuilder)var).ArgType; else if (var is LocalBuilder) return ((LocalBuilder)var).LocalType; else return var.GetType(); } internal object GetVariable(string name) { object var; if (TryGetVariable(name, out var)) return var; System.Diagnostics.Debug.Assert(false); return null; } internal bool TryGetVariable(string name, out object variable) { LocalBuilder loc; if (currentScope != null && currentScope.TryGetValue(name, out loc)) { variable = loc; return true; } ArgBuilder arg; if (argList != null && argList.TryGetValue(name, out arg)) { variable = arg; return true; } int val; if (Int32.TryParse(name, out val)) { variable = val; return true; } variable = null; return false; } #if NotUsed internal LocalBuilder DeclareLocal(Type type, string name, object initialValue) { LocalBuilder local = DeclareLocal(type, name); Load(initialValue); Store(local); return local; } #endif internal void EnterScope() { LocalScope newScope = new LocalScope(this.currentScope); this.currentScope = newScope; } internal void ExitScope() { Debug.Assert(this.currentScope.parent != null); this.currentScope.AddToFreeLocals(freeLocals); this.currentScope = this.currentScope.parent; } private bool TryDequeueLocal(Type type, string name, out LocalBuilder local) { // This method can only be called between BeginMethod and EndMethod (i.e. // while we are emitting code for a method Debug.Assert(freeLocals != null); Queue freeLocalQueue; Tuple key = new Tuple(type, name); if (freeLocals.TryGetValue(key, out freeLocalQueue)) { local = freeLocalQueue.Dequeue(); // If the queue is empty, remove this key from the dictionary // of free locals if (freeLocalQueue.Count == 0) { freeLocals.Remove(key); } return true; } local = null; return false; } internal LocalBuilder DeclareLocal(Type type, string name) { Debug.Assert(!currentScope.ContainsKey(name)); LocalBuilder local; if (!TryDequeueLocal(type, name, out local)) { local = ilGen.DeclareLocal(type, false); if (DiagnosticsSwitches.KeepTempFiles.Enabled) local.SetLocalSymInfo(name); } currentScope[name] = local; return local; } internal LocalBuilder DeclareOrGetLocal(Type type, string name) { LocalBuilder local; if (!currentScope.TryGetValue(name, out local)) local = DeclareLocal(type, name); else Debug.Assert(local.LocalType == type); return local; } #if NotUsed Dictionary parameterMapping = new Dictionary(); internal Dictionary ParameterMapping { get { return this.parameterMapping; } } internal ParameterBuilder DefineParameter(int index, ParameterAttributes attributes, string name) { if (this.parameterMapping == null) { this.parameterMapping = new Dictionary(); } this.parameterMapping.Add(name, index); return this.methodBuilder.DefineParameter(index, attributes, name); } internal void Set(LocalBuilder local, object value) { Load(value); Store(local); } #endif internal object For(LocalBuilder local, object start, object end) { ForState forState = new ForState(local, DefineLabel(), DefineLabel(), end); if (forState.Index != null) { Load(start); Stloc(forState.Index); Br(forState.TestLabel); } MarkLabel(forState.BeginLabel); blockStack.Push(forState); return forState; } internal void EndFor() { object stackTop = blockStack.Pop(); ForState forState = stackTop as ForState; Debug.Assert(forState != null); if (forState.Index != null) { Ldloc(forState.Index); Ldc(1); Add(); Stloc(forState.Index); MarkLabel(forState.TestLabel); Ldloc(forState.Index); Load(forState.End); Type varType = GetVariableType(forState.End); if (varType.IsArray) { Ldlen(); } else { #if DEBUG CodeGenerator.AssertHasInterface(varType, typeof(ICollection)); #endif MethodInfo ICollection_get_Count = typeof(ICollection).GetMethod( "get_Count", CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); Call(ICollection_get_Count); } Blt(forState.BeginLabel); } else Br(forState.BeginLabel); } #if NotUsed internal void Break(object forState) { InternalBreakFor(forState, OpCodes.Br); } internal void IfTrueBreak(object forState) { InternalBreakFor(forState, OpCodes.Brtrue); } internal void IfFalseBreak(object forState) { InternalBreakFor(forState, OpCodes.Brfalse); } internal void InternalBreakFor(object userForState, OpCode branchInstruction) { foreach (object block in blockStack) { ForState forState = block as ForState; if (forState != null && (object)forState == userForState) { if (!forState.RequiresEndLabel) { forState.EndLabel = DefineLabel(); forState.RequiresEndLabel = true; } ilGen.Emit(branchInstruction, forState.EndLabel); break; } } } internal void ForEach(LocalBuilder local, Type elementType, Type enumeratorType, LocalBuilder enumerator, MethodInfo getCurrentMethod) { ForState forState = new ForState(local, DefineLabel(), DefineLabel(), enumerator); Br(forState.TestLabel); MarkLabel(forState.BeginLabel); Call(enumerator, getCurrentMethod); ConvertValue(elementType, GetVariableType(local)); Stloc(local); blockStack.Push(forState); } internal void EndForEach(MethodInfo moveNextMethod) { object stackTop = blockStack.Pop(); ForState forState = stackTop as ForState; if (forState == null) ThrowMismatchException(stackTop); MarkLabel(forState.TestLabel); object enumerator = forState.End; Call(enumerator, moveNextMethod); Brtrue(forState.BeginLabel); if (forState.RequiresEndLabel) MarkLabel(forState.EndLabel); } internal void IfNotDefaultValue(object value) { Type type = GetVariableType(value); TypeCode typeCode = Type.GetTypeCode(type); if ((typeCode == TypeCode.Object && type.IsValueType) || typeCode == TypeCode.DateTime || typeCode == TypeCode.Decimal) { LoadDefaultValue(type); ConvertValue(type, Globals.TypeOfObject); Load(value); ConvertValue(type, Globals.TypeOfObject); Call(ObjectEquals); IfNot(); } else { LoadDefaultValue(type); Load(value); If(Cmp.NotEqualTo); } } #endif internal void If() { InternalIf(false); } internal void IfNot() { InternalIf(true); } static OpCode[] BranchCodes = new OpCode[] { OpCodes.Bge, OpCodes.Bne_Un, OpCodes.Bgt, OpCodes.Ble, OpCodes.Beq, OpCodes.Blt, }; OpCode GetBranchCode(Cmp cmp) { return BranchCodes[(int)cmp]; } #if NotUsed Cmp GetCmpInverse(Cmp cmp) { switch (cmp) { case Cmp.LessThan: return Cmp.GreaterThanOrEqualTo; case Cmp.EqualTo: return Cmp.NotEqualTo; case Cmp.LessThanOrEqualTo: return Cmp.GreaterThan; case Cmp.GreaterThan: return Cmp.LessThanOrEqualTo; case Cmp.NotEqualTo: return Cmp.EqualTo; default: Debug.Assert(cmp == Cmp.GreaterThanOrEqualTo, "Unexpected cmp"); return Cmp.LessThan; } } #endif internal void If(Cmp cmpOp) { IfState ifState = new IfState(); ifState.EndIf = DefineLabel(); ifState.ElseBegin = DefineLabel(); ilGen.Emit(GetBranchCode(cmpOp), ifState.ElseBegin); blockStack.Push(ifState); } internal void If(object value1, Cmp cmpOp, object value2) { Load(value1); Load(value2); If(cmpOp); } internal void Else() { IfState ifState = PopIfState(); Br(ifState.EndIf); MarkLabel(ifState.ElseBegin); ifState.ElseBegin = ifState.EndIf; blockStack.Push(ifState); } #if NotUsed internal void ElseIf(object value1, Cmp cmpOp, object value2) { IfState ifState = (IfState)blockStack.Pop(); Br(ifState.EndIf); MarkLabel(ifState.ElseBegin); Load(value1); Load(value2); ifState.ElseBegin = DefineLabel(); ilGen.Emit(GetBranchCode(cmpOp), ifState.ElseBegin); blockStack.Push(ifState); } #endif internal void EndIf() { IfState ifState = PopIfState(); if (!ifState.ElseBegin.Equals(ifState.EndIf)) MarkLabel(ifState.ElseBegin); MarkLabel(ifState.EndIf); } Stack leaveLabels = new Stack(); internal void BeginExceptionBlock() { leaveLabels.Push(DefineLabel()); ilGen.BeginExceptionBlock(); } internal void BeginCatchBlock(Type exception) { ilGen.BeginCatchBlock(exception); } internal void EndExceptionBlock() { ilGen.EndExceptionBlock(); ilGen.MarkLabel((Label)leaveLabels.Pop()); } internal void Leave() { ilGen.Emit(OpCodes.Leave, (Label)leaveLabels.Peek()); } #if NotUsed internal void VerifyParameterCount(MethodInfo methodInfo, int expectedCount) { if (methodInfo.GetParameters().Length != expectedCount) throw Utility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ParameterCountMismatch, methodInfo.Name, methodInfo.GetParameters().Length, expectedCount))); } internal void Call(object thisObj, MethodInfo methodInfo) { VerifyParameterCount(methodInfo, 0); LoadThis(thisObj, methodInfo); Call(methodInfo); } internal void Call(object thisObj, MethodInfo methodInfo, object param1) { VerifyParameterCount(methodInfo, 1); LoadThis(thisObj, methodInfo); LoadParam(param1, 1, methodInfo); Call(methodInfo); } internal void Call(object thisObj, MethodInfo methodInfo, object param1, object param2) { VerifyParameterCount(methodInfo, 2); LoadThis(thisObj, methodInfo); LoadParam(param1, 1, methodInfo); LoadParam(param2, 2, methodInfo); Call(methodInfo); } internal void Call(object thisObj, MethodInfo methodInfo, object param1, object param2, object param3) { VerifyParameterCount(methodInfo, 3); LoadThis(thisObj, methodInfo); LoadParam(param1, 1, methodInfo); LoadParam(param2, 2, methodInfo); LoadParam(param3, 3, methodInfo); Call(methodInfo); } internal void Call(object thisObj, MethodInfo methodInfo, object param1, object param2, object param3, object param4) { VerifyParameterCount(methodInfo, 4); LoadThis(thisObj, methodInfo); LoadParam(param1, 1, methodInfo); LoadParam(param2, 2, methodInfo); LoadParam(param3, 3, methodInfo); LoadParam(param4, 4, methodInfo); Call(methodInfo); } internal void Call(object thisObj, MethodInfo methodInfo, object param1, object param2, object param3, object param4, object param5) { VerifyParameterCount(methodInfo, 5); LoadThis(thisObj, methodInfo); LoadParam(param1, 1, methodInfo); LoadParam(param2, 2, methodInfo); LoadParam(param3, 3, methodInfo); LoadParam(param4, 4, methodInfo); LoadParam(param5, 5, methodInfo); Call(methodInfo); } internal void Call(object thisObj, MethodInfo methodInfo, object param1, object param2, object param3, object param4, object param5, object param6) { VerifyParameterCount(methodInfo, 6); LoadThis(thisObj, methodInfo); LoadParam(param1, 1, methodInfo); LoadParam(param2, 2, methodInfo); LoadParam(param3, 3, methodInfo); LoadParam(param4, 4, methodInfo); LoadParam(param5, 5, methodInfo); LoadParam(param6, 6, methodInfo); Call(methodInfo); } #endif internal void Call(MethodInfo methodInfo) { Debug.Assert(methodInfo != null); if (methodInfo.IsVirtual && !methodInfo.DeclaringType.IsValueType) ilGen.Emit(OpCodes.Callvirt, methodInfo); else ilGen.Emit(OpCodes.Call, methodInfo); } internal void Call(ConstructorInfo ctor) { Debug.Assert(ctor != null); ilGen.Emit(OpCodes.Call, ctor); } internal void New(ConstructorInfo constructorInfo) { Debug.Assert(constructorInfo != null); ilGen.Emit(OpCodes.Newobj, constructorInfo); } #if NotUsed internal void New(ConstructorInfo constructorInfo, object param1) { LoadParam(param1, 1, constructorInfo); New(constructorInfo); } #endif internal void InitObj(Type valueType) { ilGen.Emit(OpCodes.Initobj, valueType); } internal void NewArray(Type elementType, object len) { Load(len); ilGen.Emit(OpCodes.Newarr, elementType); } #if NotUsed internal void IgnoreReturnValue() { Pop(); } #endif internal void LoadArrayElement(object obj, object arrayIndex) { Type objType = GetVariableType(obj).GetElementType(); Load(obj); Load(arrayIndex); if (IsStruct(objType)) { Ldelema(objType); Ldobj(objType); } else Ldelem(objType); } internal void StoreArrayElement(object obj, object arrayIndex, object value) { Type arrayType = GetVariableType(obj); if (arrayType == typeof(Array)) { Load(obj); Call(typeof(Array).GetMethod("SetValue", new Type[] { typeof(object), typeof(int) })); } else { Type objType = arrayType.GetElementType(); Load(obj); Load(arrayIndex); if (IsStruct(objType)) Ldelema(objType); Load(value); ConvertValue(GetVariableType(value), objType); if (IsStruct(objType)) Stobj(objType); else Stelem(objType); } } static bool IsStruct(Type objType) { return objType.IsValueType && !objType.IsPrimitive; } internal Type LoadMember(object obj, MemberInfo memberInfo) { if (GetVariableType(obj).IsValueType) LoadAddress(obj); else Load(obj); return LoadMember(memberInfo); } private static MethodInfo GetPropertyMethodFromBaseType(PropertyInfo propertyInfo, bool isGetter) { // we only invoke this when the propertyInfo does not have a GET or SET method on it Type currentType = propertyInfo.DeclaringType.BaseType; PropertyInfo currentProperty; string propertyName = propertyInfo.Name; MethodInfo result = null; while (currentType != null) { currentProperty = currentType.GetProperty(propertyName); if (currentProperty != null) { if (isGetter) { result = currentProperty.GetGetMethod(true); } else { result = currentProperty.GetSetMethod(true); } if (result != null) { // we found the GetMethod/SetMethod on the type closest to the current declaring type break; } } // keep looking at the base type like compiler does currentType = currentType.BaseType; } return result; } internal Type LoadMember(MemberInfo memberInfo) { Type memberType = null; if (memberInfo.MemberType == MemberTypes.Field) { FieldInfo fieldInfo = (FieldInfo)memberInfo; memberType = fieldInfo.FieldType; if (fieldInfo.IsStatic) { ilGen.Emit(OpCodes.Ldsfld, fieldInfo); } else { ilGen.Emit(OpCodes.Ldfld, fieldInfo); } } else { System.Diagnostics.Debug.Assert(memberInfo.MemberType == MemberTypes.Property); PropertyInfo property = (PropertyInfo)memberInfo; memberType = property.PropertyType; if (property != null) { MethodInfo getMethod = property.GetGetMethod(true); if (getMethod == null) { getMethod = GetPropertyMethodFromBaseType(property, true); } System.Diagnostics.Debug.Assert(getMethod != null); Call(getMethod); } } return memberType; } internal Type LoadMemberAddress(MemberInfo memberInfo) { Type memberType = null; if (memberInfo.MemberType == MemberTypes.Field) { FieldInfo fieldInfo = (FieldInfo)memberInfo; memberType = fieldInfo.FieldType; if (fieldInfo.IsStatic) { ilGen.Emit(OpCodes.Ldsflda, fieldInfo); } else { ilGen.Emit(OpCodes.Ldflda, fieldInfo); } } else { System.Diagnostics.Debug.Assert(memberInfo.MemberType == MemberTypes.Property); PropertyInfo property = (PropertyInfo)memberInfo; memberType = property.PropertyType; if (property != null) { MethodInfo getMethod = property.GetGetMethod(true); if (getMethod == null) { getMethod = GetPropertyMethodFromBaseType(property, true); } System.Diagnostics.Debug.Assert(getMethod != null); Call(getMethod); LocalBuilder tmpLoc = GetTempLocal(memberType); Stloc(tmpLoc); Ldloca(tmpLoc); } } return memberType; } internal void StoreMember(MemberInfo memberInfo) { if (memberInfo.MemberType == MemberTypes.Field) { FieldInfo fieldInfo = (FieldInfo)memberInfo; if (fieldInfo.IsStatic) { ilGen.Emit(OpCodes.Stsfld, fieldInfo); } else { ilGen.Emit(OpCodes.Stfld, fieldInfo); } } else { System.Diagnostics.Debug.Assert(memberInfo.MemberType == MemberTypes.Property); PropertyInfo property = (PropertyInfo)memberInfo; if (property != null) { MethodInfo setMethod = property.GetSetMethod(true); if (setMethod == null) { setMethod = GetPropertyMethodFromBaseType(property, false); } System.Diagnostics.Debug.Assert(setMethod != null); Call(setMethod); } } } #if NotUsed internal void LoadDefaultValue(Type type) { if (type.IsValueType) { switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: Ldc(false); break; case TypeCode.Char: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: Ldc(0); break; case TypeCode.Int64: case TypeCode.UInt64: Ldc(0L); break; case TypeCode.Single: Ldc(0.0F); break; case TypeCode.Double: Ldc(0.0); break; case TypeCode.Decimal: case TypeCode.DateTime: default: LocalBuilder zero = DeclareLocal(type, "zero"); LoadAddress(zero); InitObj(type); Load(zero); break; } } else Load(null); } #endif internal void Load(object obj) { if (obj == null) ilGen.Emit(OpCodes.Ldnull); else if (obj is ArgBuilder) Ldarg((ArgBuilder)obj); else if (obj is LocalBuilder) Ldloc((LocalBuilder)obj); else Ldc(obj); } #if NotUsed internal void Store(object var) { if (var is ArgBuilder) Starg((ArgBuilder)var); else { System.Diagnostics.Debug.Assert(var is LocalBuilder); Stloc((LocalBuilder)var); } } internal void Dec(object var) { Load(var); Load(1); Subtract(); Store(var); } internal void Inc(object var) { Load(var); Load(1); Add(); Store(var); } #endif internal void LoadAddress(object obj) { if (obj is ArgBuilder) LdargAddress((ArgBuilder)obj); else if (obj is LocalBuilder) LdlocAddress((LocalBuilder)obj); else Load(obj); } internal void ConvertAddress(Type source, Type target) { InternalConvert(source, target, true); } internal void ConvertValue(Type source, Type target) { InternalConvert(source, target, false); } internal void Castclass(Type target) { ilGen.Emit(OpCodes.Castclass, target); } internal void Box(Type type) { ilGen.Emit(OpCodes.Box, type); } internal void Unbox(Type type) { ilGen.Emit(OpCodes.Unbox, type); } static OpCode[] LdindOpCodes = new OpCode[] { OpCodes.Nop,//Empty = 0, OpCodes.Nop,//Object = 1, OpCodes.Nop,//DBNull = 2, OpCodes.Ldind_I1,//Boolean = 3, OpCodes.Ldind_I2,//Char = 4, OpCodes.Ldind_I1,//SByte = 5, OpCodes.Ldind_U1,//Byte = 6, OpCodes.Ldind_I2,//Int16 = 7, OpCodes.Ldind_U2,//UInt16 = 8, OpCodes.Ldind_I4,//Int32 = 9, OpCodes.Ldind_U4,//UInt32 = 10, OpCodes.Ldind_I8,//Int64 = 11, OpCodes.Ldind_I8,//UInt64 = 12, OpCodes.Ldind_R4,//Single = 13, OpCodes.Ldind_R8,//Double = 14, OpCodes.Nop,//Decimal = 15, OpCodes.Nop,//DateTime = 16, OpCodes.Nop,//17 OpCodes.Ldind_Ref,//String = 18, }; OpCode GetLdindOpCode(TypeCode typeCode) { return LdindOpCodes[(int)typeCode]; //switch (typeCode) //{ //case TypeCode.Boolean: // return OpCodes.Ldind_I1; // TypeCode.Boolean: //case TypeCode.Char: // return OpCodes.Ldind_I2; // TypeCode.Char: //case TypeCode.SByte: // return OpCodes.Ldind_I1; // TypeCode.SByte: //case TypeCode.Byte: // return OpCodes.Ldind_U1; // TypeCode.Byte: //case TypeCode.Int16: // return OpCodes.Ldind_I2; // TypeCode.Int16: //case TypeCode.UInt16: // return OpCodes.Ldind_U2; // TypeCode.UInt16: //case TypeCode.Int32: // return OpCodes.Ldind_I4; // TypeCode.Int32: //case TypeCode.UInt32: // return OpCodes.Ldind_U4; // TypeCode.UInt32: //case TypeCode.Int64: // return OpCodes.Ldind_I8; // TypeCode.Int64: //case TypeCode.UInt64: // return OpCodes.Ldind_I8; // TypeCode.UInt64: //case TypeCode.Single: // return OpCodes.Ldind_R4; // TypeCode.Single: //case TypeCode.Double: // return OpCodes.Ldind_R8; // TypeCode.Double: //case TypeCode.String: // return OpCodes.Ldind_Ref; // TypeCode.String: //default: // return OpCodes.Nop; //} // } internal void Ldobj(Type type) { OpCode opCode = GetLdindOpCode(Type.GetTypeCode(type)); if (!opCode.Equals(OpCodes.Nop)) { ilGen.Emit(opCode); } else { ilGen.Emit(OpCodes.Ldobj, type); } } internal void Stobj(Type type) { ilGen.Emit(OpCodes.Stobj, type); } internal void Ceq() { ilGen.Emit(OpCodes.Ceq); } internal void Clt() { ilGen.Emit(OpCodes.Clt); } internal void Cne() { Ceq(); Ldc(0); Ceq(); } #if NotUsed internal void Bgt(Label label) { ilGen.Emit(OpCodes.Bgt, label); } #endif internal void Ble(Label label) { ilGen.Emit(OpCodes.Ble, label); } internal void Throw() { ilGen.Emit(OpCodes.Throw); } internal void Ldtoken(Type t) { ilGen.Emit(OpCodes.Ldtoken, t); } internal void Ldc(object o) { Type valueType = o.GetType(); if (o is Type) { Ldtoken((Type)o); Call(typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(RuntimeTypeHandle) }, null)); } else if (valueType.IsEnum) { Ldc(((IConvertible)o).ToType(Enum.GetUnderlyingType(valueType), null)); } else { switch (Type.GetTypeCode(valueType)) { case TypeCode.Boolean: Ldc((bool)o); break; case TypeCode.Char: Debug.Assert(false, "Char is not a valid schema primitive and should be treated as int in DataContract"); throw new NotSupportedException("Char is not a valid schema primitive and should be treated as int in DataContract"); case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: Ldc(((IConvertible)o).ToInt32(CultureInfo.InvariantCulture)); break; case TypeCode.Int32: Ldc((int)o); break; case TypeCode.UInt32: Ldc((int)(uint)o); break; case TypeCode.UInt64: Ldc((long)(ulong)o); break; case TypeCode.Int64: Ldc((long)o); break; case TypeCode.Single: Ldc((float)o); break; case TypeCode.Double: Ldc((double)o); break; case TypeCode.String: Ldstr((string)o); break; case TypeCode.Decimal: ConstructorInfo Decimal_ctor = typeof(Decimal).GetConstructor( CodeGenerator.InstanceBindingFlags, null, new Type[] { typeof(Int32), typeof(Int32), typeof(Int32), typeof(Boolean), typeof(Byte) }, null ); int[] bits = Decimal.GetBits((decimal)o); Ldc(bits[0]); // digit Ldc(bits[1]); // digit Ldc(bits[2]); // digit Ldc((bits[3] & 0x80000000) == 0x80000000); // sign Ldc((Byte)((bits[3] >> 16) & 0xFF)); // decimal location New(Decimal_ctor); break; case TypeCode.DateTime: ConstructorInfo DateTime_ctor = typeof(DateTime).GetConstructor( CodeGenerator.InstanceBindingFlags, null, new Type[] { typeof(Int64) }, null ); Ldc(((DateTime)o).Ticks); // ticks New(DateTime_ctor); break; case TypeCode.Object: case TypeCode.Empty: case TypeCode.DBNull: default: Debug.Assert(false, "UnknownConstantType"); throw new NotSupportedException("UnknownConstantType"); //.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.UnknownConstantType, DataContract.GetClrTypeFullName(valueType)))); } } } internal void Ldc(bool boolVar) { if (boolVar) { ilGen.Emit(OpCodes.Ldc_I4_1); } else { ilGen.Emit(OpCodes.Ldc_I4_0); } } internal void Ldc(int intVar) { switch (intVar) { case -1: ilGen.Emit(OpCodes.Ldc_I4_M1); break; case 0: ilGen.Emit(OpCodes.Ldc_I4_0); break; case 1: ilGen.Emit(OpCodes.Ldc_I4_1); break; case 2: ilGen.Emit(OpCodes.Ldc_I4_2); break; case 3: ilGen.Emit(OpCodes.Ldc_I4_3); break; case 4: ilGen.Emit(OpCodes.Ldc_I4_4); break; case 5: ilGen.Emit(OpCodes.Ldc_I4_5); break; case 6: ilGen.Emit(OpCodes.Ldc_I4_6); break; case 7: ilGen.Emit(OpCodes.Ldc_I4_7); break; case 8: ilGen.Emit(OpCodes.Ldc_I4_8); break; default: ilGen.Emit(OpCodes.Ldc_I4, intVar); break; } } internal void Ldc(long l) { ilGen.Emit(OpCodes.Ldc_I8, l); } internal void Ldc(float f) { ilGen.Emit(OpCodes.Ldc_R4, f); } internal void Ldc(double d) { ilGen.Emit(OpCodes.Ldc_R8, d); } internal void Ldstr(string strVar) { if (strVar == null) ilGen.Emit(OpCodes.Ldnull); else ilGen.Emit(OpCodes.Ldstr, strVar); } internal void LdlocAddress(LocalBuilder localBuilder) { if (localBuilder.LocalType.IsValueType) Ldloca(localBuilder); else Ldloc(localBuilder); } internal void Ldloc(LocalBuilder localBuilder) { ilGen.Emit(OpCodes.Ldloc, localBuilder); } internal void Ldloc(string name) { Debug.Assert(currentScope.ContainsKey(name)); LocalBuilder local = currentScope[name]; Ldloc(local); } internal void Stloc(Type type, string name) { LocalBuilder local = null; if (!currentScope.TryGetValue(name, out local)) { local = DeclareLocal(type, name); } Debug.Assert(local.LocalType == type); Stloc(local); } internal void Stloc(LocalBuilder local) { ilGen.Emit(OpCodes.Stloc, local); } internal void Ldloc(Type type, string name) { Debug.Assert(currentScope.ContainsKey(name)); LocalBuilder local = currentScope[name]; Debug.Assert(local.LocalType == type); Ldloc(local); } #if NotUsed internal void Ldloc(int slot) { switch (slot) { case 0: ilGen.Emit(OpCodes.Ldloc_0); break; case 1: ilGen.Emit(OpCodes.Ldloc_1); break; case 2: ilGen.Emit(OpCodes.Ldloc_2); break; case 3: ilGen.Emit(OpCodes.Ldloc_3); break; default: if (slot <= 255) ilGen.Emit(OpCodes.Ldloc_S, slot); else ilGen.Emit(OpCodes.Ldloc, slot); break; } } internal void Stloc(int slot) { switch (slot) { case 0: ilGen.Emit(OpCodes.Stloc_0); break; case 1: ilGen.Emit(OpCodes.Stloc_1); break; case 2: ilGen.Emit(OpCodes.Stloc_2); break; case 3: ilGen.Emit(OpCodes.Stloc_3); break; default: if (slot <= 255) ilGen.Emit(OpCodes.Stloc_S, slot); else ilGen.Emit(OpCodes.Stloc, slot); break; } } internal void Ldloca(int slot) { if (slot <= 255) ilGen.Emit(OpCodes.Ldloca_S, slot); else ilGen.Emit(OpCodes.Ldloca, slot); } #endif internal void Ldloca(LocalBuilder localBuilder) { ilGen.Emit(OpCodes.Ldloca, localBuilder); } internal void LdargAddress(ArgBuilder argBuilder) { if (argBuilder.ArgType.IsValueType) Ldarga(argBuilder); else Ldarg(argBuilder); } internal void Ldarg(string arg) { Ldarg(GetArg(arg)); } internal void Ldarg(ArgBuilder arg) { Ldarg(arg.Index); } internal void Ldarg(int slot) { switch (slot) { case 0: ilGen.Emit(OpCodes.Ldarg_0); break; case 1: ilGen.Emit(OpCodes.Ldarg_1); break; case 2: ilGen.Emit(OpCodes.Ldarg_2); break; case 3: ilGen.Emit(OpCodes.Ldarg_3); break; default: if (slot <= 255) ilGen.Emit(OpCodes.Ldarg_S, slot); else ilGen.Emit(OpCodes.Ldarg, slot); break; } } #if NotUsed internal void Starg(ArgBuilder arg) { Starg(arg.Index); } internal void Starg(int slot) { if (slot <= 255) ilGen.Emit(OpCodes.Starg_S, slot); else ilGen.Emit(OpCodes.Starg, slot); } #endif internal void Ldarga(ArgBuilder argBuilder) { Ldarga(argBuilder.Index); } internal void Ldarga(int slot) { if (slot <= 255) ilGen.Emit(OpCodes.Ldarga_S, slot); else ilGen.Emit(OpCodes.Ldarga, slot); } internal void Ldlen() { ilGen.Emit(OpCodes.Ldlen); ilGen.Emit(OpCodes.Conv_I4); } static OpCode[] LdelemOpCodes = new OpCode[] { OpCodes.Nop,//Empty = 0, OpCodes.Ldelem_Ref,//Object = 1, OpCodes.Ldelem_Ref,//DBNull = 2, OpCodes.Ldelem_I1,//Boolean = 3, OpCodes.Ldelem_I2,//Char = 4, OpCodes.Ldelem_I1,//SByte = 5, OpCodes.Ldelem_U1,//Byte = 6, OpCodes.Ldelem_I2,//Int16 = 7, OpCodes.Ldelem_U2,//UInt16 = 8, OpCodes.Ldelem_I4,//Int32 = 9, OpCodes.Ldelem_U4,//UInt32 = 10, OpCodes.Ldelem_I8,//Int64 = 11, OpCodes.Ldelem_I8,//UInt64 = 12, OpCodes.Ldelem_R4,//Single = 13, OpCodes.Ldelem_R8,//Double = 14, OpCodes.Nop,//Decimal = 15, OpCodes.Nop,//DateTime = 16, OpCodes.Nop,//17 OpCodes.Ldelem_Ref,//String = 18, }; OpCode GetLdelemOpCode(TypeCode typeCode) { return LdelemOpCodes[(int)typeCode]; //switch (typeCode) //{ //case TypeCode.Object: //case TypeCode.DBNull: // return OpCodes.Ldelem_Ref;// TypeCode.Object: //case TypeCode.Boolean: // return OpCodes.Ldelem_I1;// TypeCode.Boolean: //case TypeCode.Char: // return OpCodes.Ldelem_I2;// TypeCode.Char: //case TypeCode.SByte: // return OpCodes.Ldelem_I1;// TypeCode.SByte: //case TypeCode.Byte: // return OpCodes.Ldelem_U1;// TypeCode.Byte: //case TypeCode.Int16: // return OpCodes.Ldelem_I2;// TypeCode.Int16: //case TypeCode.UInt16: // return OpCodes.Ldelem_U2;// TypeCode.UInt16: //case TypeCode.Int32: // return OpCodes.Ldelem_I4;// TypeCode.Int32: //case TypeCode.UInt32: // return OpCodes.Ldelem_U4;// TypeCode.UInt32: //case TypeCode.Int64: // return OpCodes.Ldelem_I8;// TypeCode.Int64: //case TypeCode.UInt64: // return OpCodes.Ldelem_I8;// TypeCode.UInt64: //case TypeCode.Single: // return OpCodes.Ldelem_R4;// TypeCode.Single: //case TypeCode.Double: // return OpCodes.Ldelem_R8;// TypeCode.Double: //case TypeCode.String: // return OpCodes.Ldelem_Ref;// TypeCode.String: //default: // return OpCodes.Nop; //} } internal void Ldelem(Type arrayElementType) { if (arrayElementType.IsEnum) { Ldelem(Enum.GetUnderlyingType(arrayElementType)); } else { OpCode opCode = GetLdelemOpCode(Type.GetTypeCode(arrayElementType)); Debug.Assert(!opCode.Equals(OpCodes.Nop)); if (opCode.Equals(OpCodes.Nop)) throw new InvalidOperationException("ArrayTypeIsNotSupported"); //.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ArrayTypeIsNotSupported, DataContract.GetClrTypeFullName(arrayElementType)))); ilGen.Emit(opCode); } } internal void Ldelema(Type arrayElementType) { OpCode opCode = OpCodes.Ldelema; ilGen.Emit(opCode, arrayElementType); } static OpCode[] StelemOpCodes = new OpCode[] { OpCodes.Nop,//Empty = 0, OpCodes.Stelem_Ref,//Object = 1, OpCodes.Stelem_Ref,//DBNull = 2, OpCodes.Stelem_I1,//Boolean = 3, OpCodes.Stelem_I2,//Char = 4, OpCodes.Stelem_I1,//SByte = 5, OpCodes.Stelem_I1,//Byte = 6, OpCodes.Stelem_I2,//Int16 = 7, OpCodes.Stelem_I2,//UInt16 = 8, OpCodes.Stelem_I4,//Int32 = 9, OpCodes.Stelem_I4,//UInt32 = 10, OpCodes.Stelem_I8,//Int64 = 11, OpCodes.Stelem_I8,//UInt64 = 12, OpCodes.Stelem_R4,//Single = 13, OpCodes.Stelem_R8,//Double = 14, OpCodes.Nop,//Decimal = 15, OpCodes.Nop,//DateTime = 16, OpCodes.Nop,//17 OpCodes.Stelem_Ref,//String = 18, }; OpCode GetStelemOpCode(TypeCode typeCode) { return StelemOpCodes[(int)typeCode]; //switch (typeCode) //{ //case TypeCode.Object: //case TypeCode.DBNull: // return OpCodes.Stelem_Ref;// TypeCode.Object: //case TypeCode.Boolean: // return OpCodes.Stelem_I1;// TypeCode.Boolean: //case TypeCode.Char: // return OpCodes.Stelem_I2;// TypeCode.Char: //case TypeCode.SByte: // return OpCodes.Stelem_I1;// TypeCode.SByte: //case TypeCode.Byte: // return OpCodes.Stelem_I1;// TypeCode.Byte: //case TypeCode.Int16: // return OpCodes.Stelem_I2;// TypeCode.Int16: //case TypeCode.UInt16: // return OpCodes.Stelem_I2;// TypeCode.UInt16: //case TypeCode.Int32: // return OpCodes.Stelem_I4;// TypeCode.Int32: //case TypeCode.UInt32: // return OpCodes.Stelem_I4;// TypeCode.UInt32: //case TypeCode.Int64: // return OpCodes.Stelem_I8;// TypeCode.Int64: //case TypeCode.UInt64: // return OpCodes.Stelem_I8;// TypeCode.UInt64: //case TypeCode.Single: // return OpCodes.Stelem_R4;// TypeCode.Single: //case TypeCode.Double: // return OpCodes.Stelem_R8;// TypeCode.Double: //case TypeCode.String: // return OpCodes.Stelem_Ref;// TypeCode.String: //default: // return OpCodes.Nop; //} } internal void Stelem(Type arrayElementType) { if (arrayElementType.IsEnum) Stelem(Enum.GetUnderlyingType(arrayElementType)); else { OpCode opCode = GetStelemOpCode(Type.GetTypeCode(arrayElementType)); if (opCode.Equals(OpCodes.Nop)) throw new InvalidOperationException("ArrayTypeIsNotSupported"); //.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ArrayTypeIsNotSupported, DataContract.GetClrTypeFullName(arrayElementType)))); ilGen.Emit(opCode); } } internal Label DefineLabel() { return ilGen.DefineLabel(); } internal void MarkLabel(Label label) { ilGen.MarkLabel(label); } internal void Nop() { ilGen.Emit(OpCodes.Nop); } internal void Add() { ilGen.Emit(OpCodes.Add); } #if NotUsed internal void Subtract() { ilGen.Emit(OpCodes.Sub); } internal void And() { ilGen.Emit(OpCodes.And); } internal void Or() { ilGen.Emit(OpCodes.Or); } internal void Not() { ilGen.Emit(OpCodes.Not); } #endif internal void Ret() { ilGen.Emit(OpCodes.Ret); } internal void Br(Label label) { ilGen.Emit(OpCodes.Br, label); } internal void Br_S(Label label) { ilGen.Emit(OpCodes.Br_S, label); } internal void Blt(Label label) { ilGen.Emit(OpCodes.Blt, label); } internal void Brfalse(Label label) { ilGen.Emit(OpCodes.Brfalse, label); } internal void Brtrue(Label label) { ilGen.Emit(OpCodes.Brtrue, label); } internal void Pop() { ilGen.Emit(OpCodes.Pop); } internal void Dup() { ilGen.Emit(OpCodes.Dup); } #if !SILVERLIGHT // Not in SL internal void Ldftn(MethodInfo methodInfo) { ilGen.Emit(OpCodes.Ldftn, methodInfo); } #endif #if NotUsed void LoadThis(object thisObj, MethodInfo methodInfo) { if (thisObj != null && !methodInfo.IsStatic) { LoadAddress(thisObj); ConvertAddress(GetVariableType(thisObj), methodInfo.DeclaringType); } } void LoadParam(object arg, int oneBasedArgIndex, MethodBase methodInfo) { Load(arg); if (arg != null) ConvertValue(GetVariableType(arg), methodInfo.GetParameters()[oneBasedArgIndex - 1].ParameterType); } #endif void InternalIf(bool negate) { IfState ifState = new IfState(); ifState.EndIf = DefineLabel(); ifState.ElseBegin = DefineLabel(); if (negate) Brtrue(ifState.ElseBegin); else Brfalse(ifState.ElseBegin); blockStack.Push(ifState); } static OpCode[] ConvOpCodes = new OpCode[] { OpCodes.Nop,//Empty = 0, OpCodes.Nop,//Object = 1, OpCodes.Nop,//DBNull = 2, OpCodes.Conv_I1,//Boolean = 3, OpCodes.Conv_I2,//Char = 4, OpCodes.Conv_I1,//SByte = 5, OpCodes.Conv_U1,//Byte = 6, OpCodes.Conv_I2,//Int16 = 7, OpCodes.Conv_U2,//UInt16 = 8, OpCodes.Conv_I4,//Int32 = 9, OpCodes.Conv_U4,//UInt32 = 10, OpCodes.Conv_I8,//Int64 = 11, OpCodes.Conv_U8,//UInt64 = 12, OpCodes.Conv_R4,//Single = 13, OpCodes.Conv_R8,//Double = 14, OpCodes.Nop,//Decimal = 15, OpCodes.Nop,//DateTime = 16, OpCodes.Nop,//17 OpCodes.Nop,//String = 18, }; OpCode GetConvOpCode(TypeCode typeCode) { return ConvOpCodes[(int)typeCode]; //switch (typeCode) //{ //case TypeCode.Boolean: // return OpCodes.Conv_I1;// TypeCode.Boolean: //case TypeCode.Char: // return OpCodes.Conv_I2;// TypeCode.Char: //case TypeCode.SByte: // return OpCodes.Conv_I1;// TypeCode.SByte: //case TypeCode.Byte: // return OpCodes.Conv_U1;// TypeCode.Byte: //case TypeCode.Int16: // return OpCodes.Conv_I2;// TypeCode.Int16: //case TypeCode.UInt16: // return OpCodes.Conv_U2;// TypeCode.UInt16: //case TypeCode.Int32: // return OpCodes.Conv_I4;// TypeCode.Int32: //case TypeCode.UInt32: // return OpCodes.Conv_U4;// TypeCode.UInt32: //case TypeCode.Int64: // return OpCodes.Conv_I8;// TypeCode.Int64: //case TypeCode.UInt64: // return OpCodes.Conv_U8;// TypeCode.UInt64: //case TypeCode.Single: // return OpCodes.Conv_R4;// TypeCode.Single: //case TypeCode.Double: // return OpCodes.Conv_R8;// TypeCode.Double: //default: // return OpCodes.Nop; //} } void InternalConvert(Type source, Type target, bool isAddress) { if (target == source) return; if (target.IsValueType) { if (source.IsValueType) { OpCode opCode = GetConvOpCode(Type.GetTypeCode(target)); if (opCode.Equals(OpCodes.Nop)) { //.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.NoConversionPossibleTo, DataContract.GetClrTypeFullName(target)))); throw new CodeGeneratorConversionException(source, target, isAddress,"NoConversionPossibleTo"); } else { ilGen.Emit(opCode); } } else if (source.IsAssignableFrom(target)) { Unbox(target); if (!isAddress) Ldobj(target); } else { //.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.IsNotAssignableFrom, DataContract.GetClrTypeFullName(target), DataContract.GetClrTypeFullName(source)))); throw new CodeGeneratorConversionException(source, target, isAddress, "IsNotAssignableFrom"); } } else if (target.IsAssignableFrom(source)) { if (source.IsValueType) { if (isAddress) Ldobj(source); Box(source); } } else if (source.IsAssignableFrom(target)) { //assert(source.IsValueType == false); Castclass(target); } else if (target.IsInterface || source.IsInterface) { Castclass(target); } else { //.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.IsNotAssignableFrom, DataContract.GetClrTypeFullName(target), DataContract.GetClrTypeFullName(source)))); throw new CodeGeneratorConversionException(source, target, isAddress, "IsNotAssignableFrom"); } } IfState PopIfState() { object stackTop = blockStack.Pop(); IfState ifState = stackTop as IfState; Debug.Assert(ifState != null); return ifState; } static internal AssemblyBuilder CreateAssemblyBuilder(AppDomain appDomain, string name) { AssemblyName assemblyName = new AssemblyName(); assemblyName.Name = name; assemblyName.Version = new Version(1, 0, 0, 0); if (DiagnosticsSwitches.KeepTempFiles.Enabled) return appDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave, TempFilesLocation); else return appDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); } static string tempFilesLocation = null; internal static string TempFilesLocation { get { if (tempFilesLocation == null) { #if CONFIGURATION_DEP // Return different XmlSerializerSection from legacy assembly due to its register config handlers object section = ConfigurationManager.GetSection(ConfigurationStrings.XmlSerializerSectionPath); string location = null; if (section != null) { XmlSerializerSection configSection = section as XmlSerializerSection; if (configSection != null) { location = configSection.TempFilesLocation; } } #else string location = null; #endif if (location != null) { tempFilesLocation = location.Trim(); } else { tempFilesLocation = Path.GetTempPath(); } } return tempFilesLocation; } set { tempFilesLocation = value; } } static internal ModuleBuilder CreateModuleBuilder(AssemblyBuilder assemblyBuilder, string name) { if (DiagnosticsSwitches.KeepTempFiles.Enabled) return assemblyBuilder.DefineDynamicModule(name, name + ".dll", true); else return assemblyBuilder.DefineDynamicModule(name); } static internal TypeBuilder CreateTypeBuilder(ModuleBuilder moduleBuilder, string name, TypeAttributes attributes, Type parent, Type[] interfaces) { // parent is nullable if no base class return moduleBuilder.DefineType(TempAssembly.GeneratedAssemblyNamespace + "." + name, attributes, parent, interfaces); } #if NotUsed internal void EmitSourceInstruction(string line) { EmitSourceLine(" " + line); } internal void EmitSourceLabel(string line) { EmitSourceLine(line); } internal void EmitSourceComment(string comment) { EmitSourceInstruction("// " + comment); } internal void EmitSourceLine(string line) { if (codeGenTrace != CodeGenTrace.None) Console.WriteLine(String.Format("{0:X4}: {1}", lineNo++, line)); SerializationTrace.WriteInstruction(lineNo++, line); if (ilGen != null && codeGenTrace == CodeGenTrace.Tron) { ilGen.Emit(OpCodes.Ldstr, string.Format(CultureInfo.InvariantCulture, "{0:00000}: {1}", lineNo-1, line)); ilGen.Emit(OpCodes.Call, XmlFormatGeneratorStatics.TraceInstructionMethod); } } internal void EmitStackTop(Type stackTopType) { if (codeGenTrace != CodeGenTrace.Tron) return; codeGenTrace = CodeGenTrace.None; Dup(); ToString(stackTopType); LocalBuilder topValue = DeclareLocal(Globals.TypeOfString, "topValue"); Store(topValue); Load("//value = "); Load(topValue); Concat2(); Call(XmlFormatGeneratorStatics.TraceInstructionMethod); codeGenTrace = CodeGenTrace.Tron; } internal void ToString(Type type) { if (type.IsValueType) { Box(type); Call(ObjectToString); } else { Dup(); Load(null); If(Cmp.EqualTo); Pop(); Load(""); Else(); if (type.IsArray) { LocalBuilder arrayVar = DeclareLocal(type, "arrayVar"); Store(arrayVar); Load("{ "); LocalBuilder arrayValueString = DeclareLocal(typeof(string), "arrayValueString"); Store(arrayValueString); LocalBuilder i = DeclareLocal(typeof(int), "i"); For(i, 0, arrayVar); Load(arrayValueString); LoadArrayElement(arrayVar, i); ToString(arrayVar.LocalType.GetElementType()); Load(", "); Concat3(); Store(arrayValueString); EndFor(); Load(arrayValueString); Load("}"); Concat2(); } else Call(ObjectToString); EndIf(); } } internal void Concat2() { Call(StringConcat2); } internal void Concat3() { Call(StringConcat3); } internal Label[] Switch(int labelCount) { SwitchState switchState = new SwitchState(DefineLabel(), DefineLabel()); Label[] caseLabels = new Label[labelCount]; for (int i = 0; i < caseLabels.Length; i++) caseLabels[i] = DefineLabel(); if (codeGenTrace != CodeGenTrace.None) { EmitSourceInstruction("switch ("); foreach (Label l in caseLabels) EmitSourceInstruction(" " + l.GetHashCode()); EmitSourceInstruction(") {"); } ilGen.Emit(OpCodes.Switch, caseLabels); Br(switchState.DefaultLabel); blockStack.Push(switchState); return caseLabels; } internal void Case(Label caseLabel1, string caseLabelName) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("case " + caseLabelName + "{"); MarkLabel(caseLabel1); } internal void EndCase() { object stackTop = blockStack.Peek(); SwitchState switchState = stackTop as SwitchState; if (switchState == null) ThrowMismatchException(stackTop); Br(switchState.EndOfSwitchLabel); if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("} //end case "); } internal void DefaultCase() { object stackTop = blockStack.Peek(); SwitchState switchState = stackTop as SwitchState; if (switchState == null) ThrowMismatchException(stackTop); MarkLabel(switchState.DefaultLabel); switchState.DefaultDefined = true; } internal void EndSwitch() { object stackTop = blockStack.Pop(); SwitchState switchState = stackTop as SwitchState; if (switchState == null) ThrowMismatchException(stackTop); if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("} //end switch"); if (!switchState.DefaultDefined) MarkLabel(switchState.DefaultLabel); MarkLabel(switchState.EndOfSwitchLabel); } internal void CallStringFormat(string msg, params object[] values) { NewArray(typeof(object), values.Length); if (stringFormatArray == null) stringFormatArray = DeclareLocal(typeof(object[]), "stringFormatArray"); Stloc(stringFormatArray); for (int i = 0; i < values.Length; i++) StoreArrayElement(stringFormatArray, i, values[i]); Load(msg); Load(stringFormatArray); Call(StringFormat); } static MethodInfo stringEquals = typeof(string).GetMethod("Equals", new Type[]{ typeof(string), typeof(string)}); static MethodInfo stringCompare = typeof(string).GetMethod("Compare", new Type[]{ typeof(string), typeof(string)}); static ConstructorInfo permissionSetCtor = typeof(PermissionSet).GetConstructor(new Type[]{ typeof(PermissionState)}); static MethodInfo permissionSetDemand = typeof(PermissionSet).GetMethod("Demand", new Type[0]); #endif int initElseIfStack = -1; IfState elseIfState; internal void InitElseIf() { Debug.Assert(initElseIfStack == -1); elseIfState = (IfState)blockStack.Pop(); initElseIfStack = blockStack.Count; Br(elseIfState.EndIf); MarkLabel(elseIfState.ElseBegin); } int initIfStack = -1; internal void InitIf() { Debug.Assert(initIfStack == -1); initIfStack = blockStack.Count; } internal void AndIf(Cmp cmpOp) { if (initIfStack == blockStack.Count) { initIfStack = -1; If(cmpOp); return; } if (initElseIfStack == blockStack.Count) { initElseIfStack = -1; elseIfState.ElseBegin = DefineLabel(); ilGen.Emit(GetBranchCode(cmpOp), elseIfState.ElseBegin); blockStack.Push(elseIfState); return; } Debug.Assert(initIfStack == -1 && initElseIfStack == -1); IfState ifState = (IfState)blockStack.Peek(); ilGen.Emit(GetBranchCode(cmpOp), ifState.ElseBegin); } internal void AndIf() { if (initIfStack == blockStack.Count) { initIfStack = -1; If(); return; } if (initElseIfStack == blockStack.Count) { initElseIfStack = -1; elseIfState.ElseBegin = DefineLabel(); Brfalse(elseIfState.ElseBegin); blockStack.Push(elseIfState); return; } Debug.Assert(initIfStack == -1 && initElseIfStack == -1); IfState ifState = (IfState)blockStack.Peek(); Brfalse(ifState.ElseBegin); } #if NotUsed internal void ElseIf(object boolVal) { InternalElseIf(boolVal, false); } void InternalElseIf(object boolVal, bool negate) { IfState ifState = (IfState)blockStack.Pop(); Br(ifState.EndIf); MarkLabel(ifState.ElseBegin); Load(boolVal); ifState.ElseBegin = DefineLabel(); if (negate) Brtrue(ifState.ElseBegin); else Brfalse(ifState.ElseBegin); blockStack.Push(ifState); } internal void IfString(object s1, Cmp cmpOp, object s2) { Load(s1); Load(s2); Call(stringCompare); Load(0); If(cmpOp); } internal void ElseIfString(object s1, Cmp cmpOp, object s2) { IfState ifState = (IfState)blockStack.Pop(); Br(ifState.EndIf); MarkLabel(ifState.ElseBegin); Load(s1); Load(s2); Call(stringCompare); Load(0); ifState.ElseBegin = DefineLabel(); if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Branch if " + CmpInverse[(int) cmpOp].ToString() + " to " + ifState.ElseBegin.GetHashCode().ToString(NumberFormatInfo.InvariantInfo)); ilGen.Emit(BranchCode[(int)cmpOp], ifState.ElseBegin); blockStack.Push(ifState); } internal void While(object value1, Cmp cmpOp, object value2) { IfState ifState = new IfState(); ifState.EndIf = DefineLabel(); ifState.ElseBegin = DefineLabel(); ilGen.MarkLabel(ifState.ElseBegin); Load(value1); Load(value2); if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Branch if " + CmpInverse[(int) cmpOp].ToString() + " to " + ifState.ElseBegin.GetHashCode().ToString()); ilGen.Emit(BranchCode[(int)cmpOp], ifState.EndIf); blockStack.Push(ifState); } internal void EndWhile() { IfState ifState = PopIfState(); Br(ifState.ElseBegin); MarkLabel(ifState.EndIf); } internal void ElseIfNot(object boolVal) { InternalElseIf(boolVal, true); } internal void Ldc(long l) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldc.i8 " + l); ilGen.Emit(OpCodes.Ldc_I8, l); } internal void Ldc(float f) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldc.r4 " + f); ilGen.Emit(OpCodes.Ldc_R4, f); } internal void Ldc(double d) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldc.r8 " + d); ilGen.Emit(OpCodes.Ldc_R8, d); } #endif internal void IsInst(Type type) { ilGen.Emit(OpCodes.Isinst, type); } #if NotUsed internal void Clt() { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Clt"); ilGen.Emit(OpCodes.Clt); } internal void StringEquals() { Call(stringEquals); } internal void StringEquals(object s1, object s2) { Load(s1); ConvertValue(GetVariableType(s1), typeof(string)); Load(s2); ConvertValue(GetVariableType(s2), typeof(string)); StringEquals(); } internal void Bge(Label label) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Bge " + label.GetHashCode()); ilGen.Emit(OpCodes.Bge, label); } #endif internal void Beq(Label label) { ilGen.Emit(OpCodes.Beq, label); } internal void Bne(Label label) { ilGen.Emit(OpCodes.Bne_Un, label); } #if NotUsed internal void ResizeArray(object arrayVar, object sizeVar) { if (codeGenTrace != CodeGenTrace.None) EmitSourceComment("ResizeArray() {"); Label doResize = DefineLabel(); Load(arrayVar); Load(null); Beq(doResize); Ldlen(arrayVar); Load(sizeVar); If(Cmp.NotEqualTo); MarkLabel(doResize); Type arrayType = GetVariableType(arrayVar); Type elementType = arrayType.GetElementType(); LocalBuilder tempArray = DeclareLocal(arrayType, "tempArray"); NewArray(elementType, sizeVar); Store(tempArray); CopyArray(arrayVar, tempArray, sizeVar); Load(tempArray); Store(arrayVar); EndIf(); if (codeGenTrace != CodeGenTrace.None) EmitSourceComment("} // ResizeArray"); } LocalBuilder resizeLen, resizeCounter; internal void EnsureArrayCapacity(object arrayVar, object lastElementVar) { if (codeGenTrace != CodeGenTrace.None) EmitSourceComment("EnsureArrayCapacity() {"); Type arrayType = GetVariableType(arrayVar); Type elementType = arrayType.GetElementType(); If(arrayVar, Cmp.EqualTo, null); NewArray(elementType, 4); Store(arrayVar); Else(); Load(lastElementVar); Ldlen(arrayVar); If(Cmp.GreaterThanOrEqualTo); LocalBuilder tempArray = DeclareLocal(arrayType, "tempArray"); if (resizeLen == null) resizeLen = DeclareLocal(typeof(int), "resizeLen"); Load(lastElementVar); Load(2); Mul(); Store(resizeLen); NewArray(elementType, resizeLen); Store(tempArray); CopyArray(arrayVar, tempArray, arrayVar); Load(tempArray); Store(arrayVar); EndIf(); EndIf(); if (codeGenTrace != CodeGenTrace.None) EmitSourceComment("} // EnsureArrayCapacity"); } internal void CopyArray(object sourceArray, object destArray, object length) { If(sourceArray, Cmp.NotEqualTo, null); if (resizeCounter == null) resizeCounter = DeclareLocal(typeof(int), "resizeCounter"); For(resizeCounter, 0, length); Load(destArray); Load(resizeCounter); LoadArrayElement(sourceArray, resizeCounter); Stelem(GetVariableType(destArray).GetElementType()); EndFor(); EndIf(); } #endif internal void GotoMethodEnd() { //limit to only short forward (127 CIL instruction) //Br_S(this.methodEndLabel); Br(this.methodEndLabel); } internal class WhileState { public Label StartLabel; public Label CondLabel; public Label EndLabel; public WhileState(CodeGenerator ilg) { StartLabel = ilg.DefineLabel(); CondLabel = ilg.DefineLabel(); EndLabel = ilg.DefineLabel(); } } // Usage: // WhileBegin() // WhileBreak() // WhileContinue() // WhileBeginCondition() // (bool on stack) // WhileEndCondition() // WhileEnd() Stack whileStack; internal void WhileBegin() { WhileState whileState = new WhileState(this); Br(whileState.CondLabel); MarkLabel(whileState.StartLabel); whileStack.Push(whileState); } internal void WhileEnd() { WhileState whileState = (WhileState)whileStack.Pop(); MarkLabel(whileState.EndLabel); } internal void WhileBreak() { WhileState whileState = (WhileState)whileStack.Peek(); Br(whileState.EndLabel); } internal void WhileContinue() { WhileState whileState = (WhileState)whileStack.Peek(); Br(whileState.CondLabel); } internal void WhileBeginCondition() { WhileState whileState = (WhileState)whileStack.Peek(); // If there are two MarkLabel ILs consecutively, Labels will converge to one label. // This could cause the code to look different. We insert Nop here specifically // that the While label stands out. Nop(); MarkLabel(whileState.CondLabel); } internal void WhileEndCondition() { WhileState whileState = (WhileState)whileStack.Peek(); Brtrue(whileState.StartLabel); } #if NotUsed internal void AndWhile(Cmp cmpOp) { object startWhile = blockStack.Pop(); AndIf(cmpOp); blockStack.Push(startWhile); } internal void BeginWhileBody() { Label startWhile = (Label) blockStack.Pop(); If(); blockStack.Push(startWhile); } internal void BeginWhileBody(Cmp cmpOp) { Label startWhile = (Label) blockStack.Pop(); If(cmpOp); blockStack.Push(startWhile); } internal Label BeginWhileCondition() { Label startWhile = DefineLabel(); MarkLabel(startWhile); blockStack.Push(startWhile); return startWhile; } internal void Cne() { Ceq(); Load(0); Ceq(); } internal void New(ConstructorInfo constructorInfo, object param1, object param2) { LoadParam(param1, 1, constructorInfo); LoadParam(param2, 2, constructorInfo); New(constructorInfo); } //This code is not tested internal void Stind(Type type) { OpCode opCode = StindOpCodes[(int) Type.GetTypeCode(type)]; if (!opCode.Equals(OpCodes.Nop)) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction(opCode.ToString()); ilGen.Emit(opCode); } else { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Stobj " + type); ilGen.Emit(OpCodes.Stobj, type); } } //This code is not tested internal void StoreOutParam(ArgBuilder arg, object value) { Type destType = arg.ArgType; if (!destType.IsByRef) throw new InvalidOperationException("OutParametersMustBeByRefTypeReceived"); //.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.OutParametersMustBeByRefTypeReceived, DataContract.GetClrTypeFullName(destType)))); destType = destType.GetElementType(); Type sourceType; if (value is ArgBuilder) sourceType = ((ArgBuilder) value).ArgType; else if (value is LocalBuilder) sourceType = ((LocalBuilder) value).LocalType; else if (value != null) sourceType = value.GetType(); else sourceType = null; Load(arg); Load(value); if (sourceType != null) ConvertAddress(sourceType, destType); Stind(destType); } void CheckSecurity(FieldInfo field) { if (fullTrustDemanded) return; if (IsProtectedWithSecurity(field)) DemandFullTrust(); } void CheckSecurity(MethodBase method) { if (fullTrustDemanded) return; if (IsProtectedWithSecurity(method)) DemandFullTrust(); } void CheckSecurity(Type type) { if (fullTrustDemanded) return; if (IsProtectedWithSecurity(type)) DemandFullTrust(); } void CheckSecurity(Assembly assembly) { if (fullTrustDemanded) return; if (IsProtectedWithSecurity(assembly)) DemandFullTrust(); } static bool IsProtectedWithSecurity(FieldInfo field) { return IsProtectedWithSecurity(field.DeclaringType); } static bool IsProtectedWithSecurity(Type type) { return IsProtectedWithSecurity(type.Assembly) || (type.Attributes & TypeAttributes.HasSecurity) != 0; } static bool IsProtectedWithSecurity(Assembly assembly) { object[] attrs = assembly.GetCustomAttributes(typeof(AllowPartiallyTrustedCallersAttribute), true); bool hasAptca = attrs != null && attrs.Length > 0; return !hasAptca; } void DemandFullTrust() { fullTrustDemanded = true; /* if (codeGenTrace != CodeGenTrace.None) EmitSourceComment("DemandFullTrust() {"); Ldc(PermissionState.Unrestricted); New(permissionSetCtor); Call(permissionSetDemand); if (codeGenTrace != CodeGenTrace.None) EmitSourceComment("}"); */ } static bool IsProtectedWithSecurity(MethodBase method) { return false; //return (method.Attributes & MethodAttributes.HasSecurity) != 0; } #endif } internal class ArgBuilder { internal string Name; internal int Index; internal Type ArgType; internal ArgBuilder(string name, int index, Type argType) { this.Name = name; this.Index = index; this.ArgType = argType; } } internal class ForState { LocalBuilder indexVar; Label beginLabel; Label testLabel; object end; internal ForState(LocalBuilder indexVar, Label beginLabel, Label testLabel, object end) { this.indexVar = indexVar; this.beginLabel = beginLabel; this.testLabel = testLabel; this.end = end; } internal LocalBuilder Index { get { return indexVar; } } internal Label BeginLabel { get { return beginLabel; } } internal Label TestLabel { get { return testLabel; } } internal object End { get { return end; } } } internal enum Cmp : int { LessThan = 0, EqualTo, LessThanOrEqualTo, GreaterThan, NotEqualTo, GreaterThanOrEqualTo } internal class IfState { Label elseBegin; Label endIf; internal Label EndIf { get { return this.endIf; } set { this.endIf = value; } } internal Label ElseBegin { get { return this.elseBegin; } set { this.elseBegin = value; } } } internal class LocalScope { public readonly LocalScope parent; readonly Dictionary locals; // Root scope public LocalScope() { this.locals = new Dictionary(); } public LocalScope(LocalScope parent) : this() { this.parent = parent; } public void Add(string key, LocalBuilder value) { locals.Add(key, value); } public bool ContainsKey(string key) { return locals.ContainsKey(key) || (parent != null && parent.ContainsKey(key)); } public bool TryGetValue(string key, out LocalBuilder value) { if (locals.TryGetValue(key, out value)) { return true; } else if (parent != null) { return parent.TryGetValue(key, out value); } else { value = null; return false; } } public LocalBuilder this[string key] { get { LocalBuilder value; TryGetValue(key, out value); return value; } set { locals[key] = value; } } public void AddToFreeLocals(Dictionary, Queue> freeLocals) { foreach (var item in locals) { Tuple key = new Tuple(item.Value.LocalType, item.Key); Queue freeLocalQueue; if (freeLocals.TryGetValue(key, out freeLocalQueue)) { // Add to end of the queue so that it will be re-used in // FIFO manner freeLocalQueue.Enqueue(item.Value); } else { freeLocalQueue = new Queue(); freeLocalQueue.Enqueue(item.Value); freeLocals.Add(key, freeLocalQueue); } } } } #if NotUsed internal class BitFlagsGenerator { LocalBuilder[] locals; CodeGenerator ilg; int bitCount; internal BitFlagsGenerator(int bitCount, CodeGenerator ilg, string localName) { this.ilg = ilg; this.bitCount = bitCount; int localCount = (bitCount+7)/8; locals = new LocalBuilder[localCount]; for (int i=0;i> 3; } static byte GetBitValue(int bitIndex) { return (byte)(1 << (bitIndex & 7)); } } internal class SwitchState { Label defaultLabel; Label endOfSwitchLabel; bool defaultDefined; internal SwitchState(Label defaultLabel, Label endOfSwitchLabel) { this.defaultLabel = defaultLabel; this.endOfSwitchLabel = endOfSwitchLabel; this.defaultDefined = false; } internal Label DefaultLabel { get { return defaultLabel; } } internal Label EndOfSwitchLabel { get { return endOfSwitchLabel; } } internal bool DefaultDefined { get { return defaultDefined; } set { defaultDefined = value; } } } #endif internal class MethodBuilderInfo { public readonly MethodBuilder MethodBuilder; public readonly Type[] ParameterTypes; public MethodBuilderInfo(MethodBuilder methodBuilder, Type[] parameterTypes) { this.MethodBuilder = methodBuilder; this.ParameterTypes = parameterTypes; } public void Validate(Type returnType, Type[] parameterTypes, MethodAttributes attributes) { #if DEBUG Debug.Assert(this.MethodBuilder.ReturnType == returnType); Debug.Assert(this.MethodBuilder.Attributes == attributes); Debug.Assert(this.ParameterTypes.Length == parameterTypes.Length); for (int i = 0; i < parameterTypes.Length; ++i) { Debug.Assert(this.ParameterTypes[i] == parameterTypes[i]); } #endif } } internal class CodeGeneratorConversionException : Exception { private Type sourceType; private Type targetType; private bool isAddress; private string reason; public CodeGeneratorConversionException(Type sourceType, Type targetType, bool isAddress, string reason) : base() { this.sourceType = sourceType; this.targetType = targetType; this.isAddress = isAddress; this.reason = reason; } } }