From: Griffin C. <gc...@us...> - 2005-01-01 22:58:19
|
Update of /cvsroot/dotnetmock/dotnetmock/DotNetMock/Dynamic/Generate In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24588/DotNetMock/Dynamic/Generate Modified Files: ClassGenerator.cs Added Files: ILUtils.cs Log Message: - Merged branch RFE_1001778 into head --- NEW FILE: ILUtils.cs --- #region License // Copyright (c) 2004 Griffin Caprio & Choy Rim. All rights reserved. // until we figure out what to put here #endregion #region Imports using System; using System.Collections; using System.Reflection.Emit; #endregion namespace DotNetMock.Dynamic.Generate { /// <summary> /// Utility functions for emitting IL. /// </summary> public class ILUtils { /// <summary> /// Return appropriate ldind <see cref="OpCode"/> for type /// referenced by address on top of stack (of emitted code). /// </summary> /// <param name="referencedType">type referenced by address /// on the top of the stack (of emitted code)</param> /// <returns>appropriate ldind <see cref="OpCode"/> that will /// load the stack with value in the address that is expected /// to be on the stack</returns> /// <remarks> /// If <see cref="OpCodes.Ldobj"/> is returned, then you must /// emit the <see cref="ValueType"/> with it. /// </remarks> public static OpCode GetLdindOpCodeForType(Type referencedType) { // short-circuit reference types if ( ! referencedType.IsValueType ) { return OpCodes.Ldind_Ref; } // must be a value type // check among primitive types // ensure table is initialized if (ldindOpCodes == null) { ldindOpCodes = new Hashtable(); ldindOpCodes[typeof(sbyte)] = OpCodes.Ldind_I1; ldindOpCodes[typeof(short)] = OpCodes.Ldind_I2; ldindOpCodes[typeof(int)] = OpCodes.Ldind_I4; ldindOpCodes[typeof(long)] = OpCodes.Ldind_I8; ldindOpCodes[typeof(byte)] = OpCodes.Ldind_U1; ldindOpCodes[typeof(ushort)] = OpCodes.Ldind_U2; ldindOpCodes[typeof(uint)] = OpCodes.Ldind_U4; ldindOpCodes[typeof(ulong)] = OpCodes.Ldind_I8; ldindOpCodes[typeof(float)] = OpCodes.Ldind_R4; ldindOpCodes[typeof(double)] = OpCodes.Ldind_R8; ldindOpCodes[typeof(char)] = OpCodes.Ldind_U2; ldindOpCodes[typeof(bool)] = OpCodes.Ldind_I1; } object opCodeObject = ldindOpCodes[referencedType]; if (opCodeObject != null) { return (OpCode) opCodeObject; } // must be non-primitive ValueType return OpCodes.Ldobj; } /// <summary> /// Return appropriate stind <see cref="OpCode"/> for type /// on top of stack (of emitted code). /// </summary> /// <param name="referencedType">type /// on the top of the stack (of emitted code)</param> /// <returns>appropriate stind <see cref="OpCode"/> that will /// store the value on the stack in the address below it</returns> /// <remarks> /// If <see cref="OpCodes.Stobj"/> is returned, then you must /// emit the <see cref="ValueType"/> with it. /// </remarks> public static OpCode GetStindOpCodeForType(Type referencedType) { // short-circuit reference types if ( ! referencedType.IsValueType ) { return OpCodes.Stind_Ref; } // must be a value type, first check among primitives // ensure primitive opcodes table is initialized if (stindOpCodes == null) { stindOpCodes = new Hashtable(); stindOpCodes[typeof(sbyte)] = OpCodes.Stind_I1; stindOpCodes[typeof(short)] = OpCodes.Stind_I2; stindOpCodes[typeof(int)] = OpCodes.Stind_I4; stindOpCodes[typeof(long)] = OpCodes.Stind_I8; stindOpCodes[typeof(byte)] = OpCodes.Stind_I1; stindOpCodes[typeof(ushort)] = OpCodes.Stind_I2; stindOpCodes[typeof(uint)] = OpCodes.Stind_I4; stindOpCodes[typeof(ulong)] = OpCodes.Stind_I8; stindOpCodes[typeof(float)] = OpCodes.Stind_R4; stindOpCodes[typeof(double)] = OpCodes.Stind_R8; stindOpCodes[typeof(char)] = OpCodes.Stind_I2; stindOpCodes[typeof(bool)] = OpCodes.Stind_I1; } object opCodeObject = stindOpCodes[referencedType]; if (opCodeObject != null) { return (OpCode) opCodeObject; } // must be non-primitive ValueType return OpCodes.Stobj; } /// <summary> /// Emit the appropriate ldind instruction(s) to load the /// specified type from the address on the stack. /// </summary> /// <param name="il">generator to emit code to</param> /// <param name="referencedType">the type in the address on /// the top of the stack</param> public static void EmitTypedLdind(ILGenerator il, Type referencedType) { OpCode opCode = GetLdindOpCodeForType(referencedType); if ( opCode.Equals(OpCodes.Ldobj) ) { il.Emit(opCode, referencedType); } else { il.Emit(opCode); } } /// <summary> /// Emit the appropriate stind instruction(s) to store the /// specified type from the top of the stack to the address /// bwlow it. /// </summary> /// <param name="il">generator to emit code to</param> /// <param name="referencedType">type of the value on the top of /// the stack</param> public static void EmitTypedStind(ILGenerator il, Type referencedType) { OpCode opCode = GetStindOpCodeForType(referencedType); if ( opCode.Equals(OpCodes.Stobj) ) { il.Emit(opCode, referencedType); } else { il.Emit(opCode); } } private static IDictionary ldindOpCodes = null; private static IDictionary stindOpCodes = null; } } Index: ClassGenerator.cs =================================================================== RCS file: /cvsroot/dotnetmock/dotnetmock/DotNetMock/Dynamic/Generate/ClassGenerator.cs,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** ClassGenerator.cs 1 Jan 2005 21:13:51 -0000 1.7 --- ClassGenerator.cs 1 Jan 2005 22:58:08 -0000 1.8 *************** *** 1,6 **** --- 1,12 ---- + #region License + // Copyright (c) 2004 Griffin Caprio & Choy Rim. All rights reserved. + #endregion + #region Imports using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; + using DotNetMock.Dynamic; + #endregion namespace DotNetMock.Dynamic.Generate *************** *** 11,29 **** public class ClassGenerator { ! private static IDictionary boxingOpCodes; /// <summary> ! /// Generates a proxy object for the input type, using the input <see cref="IDynamicMock"/> implementation. /// </summary> ! /// <param name="type"><see cref="System.Type"/> to generate proxy object for.</param> ! /// <param name="mock"><see cref="IDynamicMock"/> object containing the parameters for the proxy object</param> ! /// <returns>Generated proxy object</returns> ! public object Generate(Type type, IDynamicMock mock) { TypeBuilder typeBuilder = getTypeBuilder("Mock" + type.Name, type); ! FieldBuilder mockFieldBuilder = typeBuilder.DefineField("underlyingMock", typeof(IDynamicMock), FieldAttributes.Public); IList methods = getMethods(type); foreach ( MethodInfo m in methods ) { ! implementMethod(type, typeBuilder, m, mockFieldBuilder); } Type proxyType = typeBuilder.CreateType(); --- 17,57 ---- public class ClassGenerator { ! AssemblyBuilder _assemblyBuilder = null; ! ModuleBuilder _moduleBuilder = null; ! string _assemblyFilename = null; ! /// <summary> ! /// Create default instance of mock object generator. /// </summary> ! public ClassGenerator() ! { ! _assemblyBuilder = newAssemblyBuilder(AssemblyBuilderAccess.Run); ! _moduleBuilder = _assemblyBuilder.DefineDynamicModule("MockModule"); ! } ! ! /// <summary> ! /// Create mock object generator that can save. ! /// </summary> ! /// <param name="filename">filename to save to</param> ! public ClassGenerator(string filename) ! { ! _assemblyBuilder = newAssemblyBuilder(AssemblyBuilderAccess.RunAndSave); ! _moduleBuilder = _assemblyBuilder.DefineDynamicModule("MockModule", filename); ! _assemblyFilename = filename; ! } ! /// <summary> ! /// Generates proxy mock object for the input type using the parameters from the <see cref="IMockedCallHandler"/> ! /// </summary> ! /// <param name="type">type to generate proxy for.</param> ! /// <param name="mock"><see cref="IMockedCallHandler"/> containg parameters for proxy object.</param> ! /// <returns>proxy mock object for input type.</returns> ! public object Generate(Type type, IMockedCallHandler mock) { TypeBuilder typeBuilder = getTypeBuilder("Mock" + type.Name, type); ! FieldBuilder mockFieldBuilder = typeBuilder.DefineField("underlyingMock", typeof(IMockedCallHandler), FieldAttributes.Public); IList methods = getMethods(type); foreach ( MethodInfo m in methods ) { ! implementMethod(typeBuilder, m, mockFieldBuilder); } Type proxyType = typeBuilder.CreateType(); *************** *** 31,34 **** --- 59,66 ---- FieldInfo underlyingMock = proxyType.GetField("underlyingMock"); underlyingMock.SetValue(result, mock); + if ( _assemblyFilename!=null ) + { + _assemblyBuilder.Save(_assemblyFilename); + } return result; } *************** *** 59,67 **** private TypeBuilder getTypeBuilder(string name, Type originalType) { - AppDomain appDomain = AppDomain.CurrentDomain; - AssemblyName assemblyName = new AssemblyName(); - assemblyName.Name = "DynamicMockAssembly"; - AssemblyBuilder assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); - ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MockModule"); Type superClass; Type[] interfaces; --- 91,94 ---- *************** *** 76,83 **** interfaces = new Type[0]; } ! return moduleBuilder.DefineType(name, TypeAttributes.Public, superClass, interfaces); } ! private void implementMethod(Type type, TypeBuilder typeBuilder, MethodInfo m, FieldBuilder mockFieldBuilder) { Type returnType = m.ReturnType; --- 103,110 ---- interfaces = new Type[0]; } ! return _moduleBuilder.DefineType(name, TypeAttributes.Public, superClass, interfaces); } ! private void implementMethod(TypeBuilder typeBuilder, MethodInfo m, FieldBuilder mockFieldBuilder) { Type returnType = m.ReturnType; *************** *** 94,97 **** --- 121,125 ---- il.DeclareLocal(typeof(object[])); + // TODO: why are we declaring all these locals? foreach (ParameterInfo param in m.GetParameters()) { *************** *** 99,133 **** } - string methodName = m.Name; - if (methodName.StartsWith("get_") || methodName.StartsWith("set_")) - { - methodName = methodName.Substring(4); - } - il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, mockFieldBuilder); ! il.Emit(OpCodes.Ldstr, methodName); ! il.Emit(OpCodes.Ldc_I4_S, paramTypes.Length); il.Emit(OpCodes.Newarr, typeof(object)); if (paramTypes.Length > 0) { - il.Emit(OpCodes.Stloc_0); - il.Emit(OpCodes.Ldloc_0); - for(int i = 0; i < paramTypes.Length; i++) { ! il.Emit(OpCodes.Ldc_I4_S, i); ! il.Emit(OpCodes.Ldarg_S, i + 1); ! if (paramTypes[i].IsValueType) { ! il.Emit(OpCodes.Box, paramTypes[i]); } il.Emit(OpCodes.Stelem_Ref); - il.Emit(OpCodes.Ldloc_0); } } ! MethodInfo call = typeof(IDynamicMock).GetMethod("Call"); il.EmitCall(OpCodes.Callvirt, call, null); --- 127,171 ---- } il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, mockFieldBuilder); ! // emit call to get current method ! il.EmitCall( ! OpCodes.Call, ! typeof(MethodBase).GetMethod("GetCurrentMethod", new Type[0]), ! null ! ); ! // assert paramTypes.Length<128 ! il.Emit(OpCodes.Ldc_I4_S, (sbyte) paramTypes.Length); il.Emit(OpCodes.Newarr, typeof(object)); + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Stloc_0); if (paramTypes.Length > 0) { for(int i = 0; i < paramTypes.Length; i++) { ! Type paramType = paramTypes[i]; ! Type elementType = paramType; ! // push array ref onto stack ! il.Emit(OpCodes.Ldloc_0); ! // push array index onto stack ! il.Emit(OpCodes.Ldc_I4_S, (sbyte) i); ! // load corresponding argument ! il.Emit(OpCodes.Ldarg_S, (sbyte) (i + 1)); ! // dereference if necessary ! if ( paramType.IsByRef ) { ! elementType = paramType.GetElementType(); ! ILUtils.EmitTypedLdind(il, elementType); ! } ! if ( elementType.IsValueType ) ! { ! il.Emit(OpCodes.Box, elementType); } il.Emit(OpCodes.Stelem_Ref); } } ! MethodInfo call = typeof(IMockedCallHandler).GetMethod("Call", new Type[] {typeof(MethodInfo), typeof(object[]) } ); il.EmitCall(OpCodes.Callvirt, call, null); *************** *** 141,199 **** { il.Emit(OpCodes.Unbox, returnType); ! if (returnType.IsPrimitive) ! { ! il.Emit(GetBoxingOpCode(returnType)); ! } ! else { ! il.Emit(GetBoxingOpCode(returnType), returnType); } } } il.Emit(OpCodes.Ret); } ! /// <summary> ! /// Returns the IL <see cref="System.Reflection.Emit.OpCode"/> for the input type. ! /// </summary> ! /// <param name="currentType">Type to return op code for.</param> ! /// <returns>Op Code for input type.</returns> ! public OpCode GetBoxingOpCode( Type currentType ) { ! if (boxingOpCodes == null) ! { ! boxingOpCodes = new Hashtable(); ! boxingOpCodes[typeof(sbyte)] = OpCodes.Ldind_I1; ! boxingOpCodes[typeof(short)] = OpCodes.Ldind_I2; ! boxingOpCodes[typeof(int)] = OpCodes.Ldind_I4; ! boxingOpCodes[typeof(long)] = OpCodes.Ldind_I8; ! boxingOpCodes[typeof(byte)] = OpCodes.Ldind_U1; ! boxingOpCodes[typeof(ushort)] = OpCodes.Ldind_U2; ! boxingOpCodes[typeof(uint)] = OpCodes.Ldind_U4; ! boxingOpCodes[typeof(ulong)] = OpCodes.Ldind_I8; ! boxingOpCodes[typeof(float)] = OpCodes.Ldind_R4; ! boxingOpCodes[typeof(double)] = OpCodes.Ldind_R8; ! boxingOpCodes[typeof(char)] = OpCodes.Ldind_U2; ! boxingOpCodes[typeof(bool)] = OpCodes.Ldind_I1; ! } ! ! OpCode opCode; ! object opCodeObject = boxingOpCodes[currentType]; ! ! if (opCodeObject != null) ! { ! opCode = (OpCode)opCodeObject; ! } ! else if (!currentType.IsValueType) ! { ! opCode = OpCodes.Ldind_I1; ! } ! else ! { ! opCode = OpCodes.Ldobj; ! } ! ! return opCode; } - } --- 179,222 ---- { il.Emit(OpCodes.Unbox, returnType); ! // load boxed value from heap ! ILUtils.EmitTypedLdind(il, returnType); ! } ! } ! // load out/ref parameter values ! if (paramTypes.Length > 0) ! { ! for(int i = 0; i < paramTypes.Length; i++) ! { ! Type paramType = paramTypes[i]; ! if ( paramType.IsByRef ) { ! Type elementType = paramType.GetElementType(); ! // address of byref arg ! il.Emit(OpCodes.Ldarg_S, (sbyte) (i+1)); ! // fetch value from args array ! il.Emit(OpCodes.Ldloc_0); ! il.Emit(OpCodes.Ldc_I4_S, (sbyte) i); ! il.Emit(OpCodes.Ldelem_Ref); ! // unbox if necessary ! if ( elementType.IsValueType ) ! { ! il.Emit(OpCodes.Unbox, elementType); ! ILUtils.EmitTypedLdind(il, elementType); ! } ! // store indirectly into ref arg ! ILUtils.EmitTypedStind(il, elementType); } } } + il.Emit(OpCodes.Ret); } ! private static AssemblyBuilder newAssemblyBuilder(AssemblyBuilderAccess access) { ! AppDomain appDomain = AppDomain.CurrentDomain; ! AssemblyName assemblyName = new AssemblyName(); ! assemblyName.Name = "DynamicMockAssembly"; ! return appDomain.DefineDynamicAssembly( assemblyName, access ); } } |