//----------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- // ***NOTE*** If this code is changed, make corresponding changes in System.Runtime.Serialization.CodeGenerator also namespace System.ServiceModel.Dispatcher { using System; using System.Collections; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Reflection.Emit; using System.Runtime; using System.Security; using System.ServiceModel.Diagnostics; [Fx.Tag.SecurityNote(Critical = "Generates IL into an ILGenerator that was created under an Assert." + "Generated IL must be correct and must not subvert the type system.")] #pragma warning disable 618 // have not moved to the v4 security model yet [SecurityCritical(SecurityCriticalScope.Everything)] #pragma warning restore 618 internal class CodeGenerator { static MethodInfo getTypeFromHandle; static MethodInfo stringConcat2; static MethodInfo objectToString; static MethodInfo boxPointer; static MethodInfo unboxPointer; #if USE_REFEMIT AssemblyBuilder assemblyBuilder; ModuleBuilder moduleBuilder; TypeBuilder typeBuilder; static int typeCounter; MethodBuilder methodBuilder; #else static Module SerializationModule = typeof(CodeGenerator).Module; // Can be replaced by different assembly with SkipVerification set to false DynamicMethod dynamicMethod; #if DEBUG bool allowPrivateMemberAccess; #endif #endif Type delegateType; ILGenerator ilGen; ArrayList argList; Stack blockStack; Label methodEndLabel; Hashtable localNames; int lineNo = 1; enum CodeGenTrace { None, Save, Tron }; CodeGenTrace codeGenTrace; internal CodeGenerator() { SourceSwitch codeGenSwitch = OperationInvokerTrace.CodeGenerationSwitch; if ((codeGenSwitch.Level & SourceLevels.Verbose) == SourceLevels.Verbose) codeGenTrace = CodeGenTrace.Tron; else if ((codeGenSwitch.Level & SourceLevels.Information) == SourceLevels.Information) codeGenTrace = CodeGenTrace.Save; else codeGenTrace = CodeGenTrace.None; } static MethodInfo GetTypeFromHandle { get { if (getTypeFromHandle == null) getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle"); return getTypeFromHandle; } } static MethodInfo StringConcat2 { get { if (stringConcat2 == null) stringConcat2 = typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }); return stringConcat2; } } static MethodInfo ObjectToString { get { if (objectToString == null) objectToString = typeof(object).GetMethod("ToString", new Type[0]); return objectToString; } } static MethodInfo BoxPointer { get { if (boxPointer == null) boxPointer = typeof(Pointer).GetMethod("Box"); return boxPointer; } } static MethodInfo UnboxPointer { get { if (unboxPointer == null) unboxPointer = typeof(Pointer).GetMethod("Unbox"); return unboxPointer; } } internal void BeginMethod(string methodName, Type delegateType, bool allowPrivateMemberAccess) { MethodInfo signature = delegateType.GetMethod("Invoke"); ParameterInfo[] parameters = signature.GetParameters(); Type[] paramTypes = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) paramTypes[i] = parameters[i].ParameterType; BeginMethod(signature.ReturnType, methodName, paramTypes, allowPrivateMemberAccess); this.delegateType = delegateType; } void BeginMethod(Type returnType, string methodName, Type[] argTypes, bool allowPrivateMemberAccess) { #if USE_REFEMIT string typeName = "Type" + (typeCounter++); InitAssemblyBuilder(typeName + "." + methodName); this.typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public); this.methodBuilder = typeBuilder.DefineMethod(methodName, MethodAttributes.Public|MethodAttributes.Static, returnType, argTypes); this.ilGen = this.methodBuilder.GetILGenerator(); #else this.dynamicMethod = new DynamicMethod(methodName, returnType, argTypes, SerializationModule, allowPrivateMemberAccess); this.ilGen = this.dynamicMethod.GetILGenerator(); #if DEBUG this.allowPrivateMemberAccess = allowPrivateMemberAccess; #endif #endif this.methodEndLabel = ilGen.DefineLabel(); this.blockStack = new Stack(); this.argList = new ArrayList(); for (int i = 0; i < argTypes.Length; i++) argList.Add(new ArgBuilder(i, argTypes[i])); if (codeGenTrace != CodeGenTrace.None) EmitSourceLabel("Begin method " + methodName + " {"); } internal Delegate EndMethod() { MarkLabel(methodEndLabel); if (codeGenTrace != CodeGenTrace.None) EmitSourceLabel("} End method"); Ret(); Delegate retVal = null; #if USE_REFEMIT Type type = typeBuilder.CreateType(); if (codeGenTrace != CodeGenTrace.None) assemblyBuilder.Save(assemblyBuilder.GetName().Name+".dll"); MethodInfo method = type.GetMethod(methodBuilder.Name); retVal = Delegate.CreateDelegate(delegateType, method); methodBuilder = null; #else retVal = dynamicMethod.CreateDelegate(delegateType); dynamicMethod = null; #endif delegateType = null; ilGen = null; blockStack = null; argList = null; return retVal; } internal MethodInfo CurrentMethod { get { #if USE_REFEMIT return methodBuilder; #else return dynamicMethod; #endif } } internal ArgBuilder GetArg(int index) { return (ArgBuilder)argList[index]; } 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 LocalBuilder DeclareLocal(Type type, string name) { return DeclareLocal(type, name, false); } internal LocalBuilder DeclareLocal(Type type, string name, bool isPinned) { LocalBuilder local = ilGen.DeclareLocal(type, isPinned); if (codeGenTrace != CodeGenTrace.None) { LocalNames[local] = name; EmitSourceComment("Declare local '" + name + "' of type " + type); } return local; } internal void If() { InternalIf(false); } internal void IfNot() { InternalIf(true); } internal void Else() { IfState ifState = PopIfState(); Br(ifState.EndIf); MarkLabel(ifState.ElseBegin); ifState.ElseBegin = ifState.EndIf; blockStack.Push(ifState); } internal void EndIf() { IfState ifState = PopIfState(); if (!ifState.ElseBegin.Equals(ifState.EndIf)) MarkLabel(ifState.ElseBegin); MarkLabel(ifState.EndIf); } internal void Call(MethodInfo methodInfo) { if (methodInfo.IsVirtual) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Callvirt " + methodInfo.ToString() + " on type " + methodInfo.DeclaringType.ToString()); ilGen.Emit(OpCodes.Callvirt, methodInfo); } else if (methodInfo.IsStatic) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Static Call " + methodInfo.ToString() + " on type " + methodInfo.DeclaringType.ToString()); ilGen.Emit(OpCodes.Call, methodInfo); } else { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Call " + methodInfo.ToString() + " on type " + methodInfo.DeclaringType.ToString()); ilGen.Emit(OpCodes.Call, methodInfo); } } internal void New(ConstructorInfo constructor) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Newobj " + constructor.ToString() + " on type " + constructor.DeclaringType.ToString()); ilGen.Emit(OpCodes.Newobj, constructor); } internal void InitObj(Type valueType) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Initobj " + valueType); ilGen.Emit(OpCodes.Initobj, valueType); } 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 objType = GetVariableType(obj).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 void Load(object obj) { if (obj == null) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldnull"); ilGen.Emit(OpCodes.Ldnull); } else if (obj is ArgBuilder) Ldarg((ArgBuilder)obj); else if (obj is LocalBuilder) Ldloc((LocalBuilder)obj); else Ldc(obj); } internal void Store(object var) { if (var is ArgBuilder) Starg((ArgBuilder)var); else if (var is LocalBuilder) Stloc((LocalBuilder)var); else throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxCodeGenCanOnlyStoreIntoArgOrLocGot0, var.GetType().FullName))); } 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) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Castclass " + target); ilGen.Emit(OpCodes.Castclass, target); } internal void Box(Type type) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Box " + type); ilGen.Emit(OpCodes.Box, type); } internal void Unbox(Type type) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Unbox " + type); ilGen.Emit(OpCodes.Unbox, type); } internal void Ldobj(Type type) { OpCode opCode = GetLdindOpCode(Type.GetTypeCode(type)); if (!opCode.Equals(OpCodes.Nop)) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction(opCode.ToString()); ilGen.Emit(opCode); } else { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldobj " + type); ilGen.Emit(OpCodes.Ldobj, type); } } internal void Stobj(Type type) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Stobj " + type); ilGen.Emit(OpCodes.Stobj, type); } internal void Ldtoken(Type t) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldtoken " + t); ilGen.Emit(OpCodes.Ldtoken, t); } internal void Ldc(object o) { Type valueType = o.GetType(); if (o is Type) { Ldtoken((Type)o); Call(GetTypeFromHandle); } else if (valueType.IsEnum) { if (codeGenTrace != CodeGenTrace.None) EmitSourceComment("Ldc " + o.GetType() + "." + o); Ldc(((IConvertible)o).ToType(Enum.GetUnderlyingType(valueType), null)); } else { switch (Type.GetTypeCode(valueType)) { case TypeCode.Boolean: Ldc((bool)o); break; case TypeCode.Char: Ldc((int)(char)o); break; 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.String: Ldstr((string)o); break; case TypeCode.UInt64: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Object: case TypeCode.Decimal: case TypeCode.DateTime: case TypeCode.Empty: case TypeCode.DBNull: default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxCodeGenUnknownConstantType, valueType.FullName))); } } } internal void Ldc(bool boolVar) { if (boolVar) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldc.i4 1"); ilGen.Emit(OpCodes.Ldc_I4_1); } else { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldc.i4 0"); ilGen.Emit(OpCodes.Ldc_I4_0); } } internal void Ldc(int intVar) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldc.i4 " + 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 Ldstr(string strVar) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldstr " + strVar); ilGen.Emit(OpCodes.Ldstr, strVar); } internal void LdlocAddress(LocalBuilder localBuilder) { if (localBuilder.LocalType.IsValueType) Ldloca(localBuilder); else Ldloc(localBuilder); } internal void Ldloc(LocalBuilder localBuilder) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldloc " + LocalNames[localBuilder]); ilGen.Emit(OpCodes.Ldloc, localBuilder); EmitStackTop(localBuilder.LocalType); } internal void Stloc(LocalBuilder local) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Stloc " + LocalNames[local]); EmitStackTop(local.LocalType); ilGen.Emit(OpCodes.Stloc, local); } internal void Ldloc(int slot) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldloc " + 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) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Stloc " + 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(LocalBuilder localBuilder) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldloca " + LocalNames[localBuilder]); ilGen.Emit(OpCodes.Ldloca, localBuilder); EmitStackTop(localBuilder.LocalType); } internal void Ldloca(int slot) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldloca " + slot); if (slot <= 255) ilGen.Emit(OpCodes.Ldloca_S, slot); else ilGen.Emit(OpCodes.Ldloca, slot); } internal void LdargAddress(ArgBuilder argBuilder) { if (argBuilder.ArgType.IsValueType) Ldarga(argBuilder); else Ldarg(argBuilder); } internal void Ldarg(ArgBuilder arg) { Ldarg(arg.Index); } internal void Starg(ArgBuilder arg) { Starg(arg.Index); } internal void Ldarg(int slot) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldarg " + 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; } } internal void Starg(int slot) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Starg " + slot); if (slot <= 255) ilGen.Emit(OpCodes.Starg_S, slot); else ilGen.Emit(OpCodes.Starg, slot); } internal void Ldarga(ArgBuilder argBuilder) { Ldarga(argBuilder.Index); } internal void Ldarga(int slot) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldarga " + slot); if (slot <= 255) ilGen.Emit(OpCodes.Ldarga_S, slot); else ilGen.Emit(OpCodes.Ldarga, slot); } internal void Ldelem(Type arrayElementType) { if (arrayElementType.IsEnum) { Ldelem(Enum.GetUnderlyingType(arrayElementType)); } else { OpCode opCode = GetLdelemOpCode(Type.GetTypeCode(arrayElementType)); if (opCode.Equals(OpCodes.Nop)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxCodeGenArrayTypeIsNotSupported, arrayElementType.FullName))); if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction(opCode.ToString()); ilGen.Emit(opCode); EmitStackTop(arrayElementType); } } internal void Ldelema(Type arrayElementType) { OpCode opCode = OpCodes.Ldelema; if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction(opCode.ToString()); ilGen.Emit(opCode, arrayElementType); EmitStackTop(arrayElementType); } 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 DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxCodeGenArrayTypeIsNotSupported, arrayElementType.FullName))); if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction(opCode.ToString()); EmitStackTop(arrayElementType); ilGen.Emit(opCode); } } internal Label DefineLabel() { return ilGen.DefineLabel(); } internal void MarkLabel(Label label) { ilGen.MarkLabel(label); if (codeGenTrace != CodeGenTrace.None) EmitSourceLabel(label.GetHashCode() + ":"); } internal void Ret() { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ret"); ilGen.Emit(OpCodes.Ret); } internal void Br(Label label) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Br " + label.GetHashCode()); ilGen.Emit(OpCodes.Br, label); } internal void Brfalse(Label label) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Brfalse " + label.GetHashCode()); ilGen.Emit(OpCodes.Brfalse, label); } internal void Brtrue(Label label) { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Brtrue " + label.GetHashCode()); ilGen.Emit(OpCodes.Brtrue, label); } internal void Pop() { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Pop"); ilGen.Emit(OpCodes.Pop); } internal void Dup() { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Dup"); ilGen.Emit(OpCodes.Dup); } 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); } 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)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxCodeGenNoConversionPossibleTo, target.FullName))); else { if (codeGenTrace != CodeGenTrace.None) EmitSourceInstruction(opCode.ToString()); ilGen.Emit(opCode); } } else if (source.IsAssignableFrom(target)) { Unbox(target); if (!isAddress) Ldobj(target); } else throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxCodeGenIsNotAssignableFrom, target.FullName, source.FullName))); } else if (target.IsPointer) { Call(UnboxPointer); } else if (source.IsPointer) { Load(source); Call(BoxPointer); } 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 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxCodeGenIsNotAssignableFrom, target.FullName, source.FullName))); } IfState PopIfState() { object stackTop = blockStack.Pop(); IfState ifState = stackTop as IfState; if (ifState == null) ThrowMismatchException(stackTop); return ifState; } #if USE_REFEMIT void InitAssemblyBuilder(string methodName) { //if (assemblyBuilder == null) { AssemblyName name = new AssemblyName(); name.Name = "Microsoft.GeneratedCode."+methodName; bool saveAssembly = false; if (codeGenTrace != CodeGenTrace.None) saveAssembly = true; if (saveAssembly) { assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave); moduleBuilder = assemblyBuilder.DefineDynamicModule(name.Name, name.Name + ".dll", false); } else { assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); moduleBuilder = assemblyBuilder.DefineDynamicModule(name.Name, false); } //} } #endif void ThrowMismatchException(object expected) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxCodeGenExpectingEnd, expected.ToString()))); } Hashtable LocalNames { get { if (localNames == null) localNames = new Hashtable(); return localNames; } } OpCode GetConvOpCode(TypeCode 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_I8; // TypeCode.UInt64: case TypeCode.Single: return OpCodes.Conv_R4; // TypeCode.Single: case TypeCode.Double: return OpCodes.Conv_R8; // TypeCode.Double: default: return OpCodes.Nop; } } OpCode GetLdindOpCode(TypeCode 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; } // } OpCode GetLdelemOpCode(TypeCode typeCode) { switch (typeCode) { case TypeCode.Object: 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; } } OpCode GetStelemOpCode(TypeCode typeCode) { switch (typeCode) { case TypeCode.Object: 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 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) OperationInvokerTrace.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, OperationInvokerTrace.TraceInstructionMethod); } } internal void EmitStackTop(Type stackTopType) { if (codeGenTrace != CodeGenTrace.Tron) return; codeGenTrace = CodeGenTrace.None; Dup(); ToString(stackTopType); LocalBuilder topValue = DeclareLocal(typeof(string), "topValue"); Store(topValue); Load("//value = "); Load(topValue); Concat2(); Call(OperationInvokerTrace.TraceInstructionMethod); codeGenTrace = CodeGenTrace.Tron; } internal void ToString(Type type) { if (type.IsValueType) { Box(type); Call(ObjectToString); } else { Dup(); IfNot(); Pop(); Load(""); Else(); Call(ObjectToString); EndIf(); } } internal void Concat2() { Call(StringConcat2); } internal void LoadZeroValueIntoLocal(Type type, LocalBuilder local) { if (type.IsValueType) { switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: ilGen.Emit(OpCodes.Ldc_I4_0); Store(local); break; case TypeCode.Int64: case TypeCode.UInt64: ilGen.Emit(OpCodes.Ldc_I4_0); ilGen.Emit(OpCodes.Conv_I8); Store(local); break; case TypeCode.Single: ilGen.Emit(OpCodes.Ldc_R4, 0.0F); Store(local); break; case TypeCode.Double: ilGen.Emit(OpCodes.Ldc_R8, 0.0); Store(local); break; case TypeCode.Decimal: case TypeCode.DateTime: default: LoadAddress(local); InitObj(type); break; } } else { Load(null); Store(local); } } } internal class ArgBuilder { internal int Index; internal Type ArgType; internal ArgBuilder(int index, Type argType) { this.Index = index; this.ArgType = argType; } } 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; } } } }