using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Threading; namespace LuaInterface { internal class CodeGeneration { private Type eventHandlerParent = typeof(LuaEventHandler); private Dictionary eventHandlerCollection = new Dictionary(); private Type delegateParent = typeof(LuaDelegate); private Dictionary delegateCollection = new Dictionary(); private Type classHelper = typeof(LuaClassHelper); private Dictionary classCollection = new Dictionary(); private AssemblyName assemblyName; private AssemblyBuilder newAssembly; private ModuleBuilder newModule; private int luaClassNumber = 1; private static readonly CodeGeneration instance; public static CodeGeneration Instance { get { return instance; } } private CodeGeneration() { assemblyName = new AssemblyName(); assemblyName.Name = "LuaInterface_generatedcode"; newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); newModule = newAssembly.DefineDynamicModule("LuaInterface_generatedcode"); } static CodeGeneration() { instance = new CodeGeneration(); } private Type GenerateEvent(Type eventHandlerType) { string name; lock (this) { name = "LuaGeneratedClass" + luaClassNumber; luaClassNumber++; } TypeBuilder typeBuilder = newModule.DefineType(name, TypeAttributes.Public, eventHandlerParent); Type[] parameterTypes = new Type[2] { typeof(object), eventHandlerType }; Type typeFromHandle = typeof(void); MethodBuilder methodBuilder = typeBuilder.DefineMethod("HandleEvent", MethodAttributes.Public | MethodAttributes.HideBySig, typeFromHandle, parameterTypes); ILGenerator iLGenerator = methodBuilder.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Ldarg_2); MethodInfo method = eventHandlerParent.GetMethod("handleEvent"); iLGenerator.Emit(OpCodes.Call, method); iLGenerator.Emit(OpCodes.Ret); return typeBuilder.CreateType(); } private Type GenerateDelegate(Type delegateType) { string name; lock (this) { name = "LuaGeneratedClass" + luaClassNumber; luaClassNumber++; } TypeBuilder typeBuilder = newModule.DefineType(name, TypeAttributes.Public, delegateParent); MethodInfo method = delegateType.GetMethod("Invoke"); ParameterInfo[] parameters = method.GetParameters(); Type[] array = new Type[parameters.Length]; Type returnType = method.ReturnType; int num = 0; int num2 = 0; for (int i = 0; i < array.Length; i++) { array[i] = parameters[i].ParameterType; if (!parameters[i].IsIn && parameters[i].IsOut) { num++; } if (array[i].IsByRef) { num2++; } } int[] array2 = new int[num2]; MethodBuilder methodBuilder = typeBuilder.DefineMethod("CallFunction", method.Attributes, returnType, array); ILGenerator iLGenerator = methodBuilder.GetILGenerator(); iLGenerator.DeclareLocal(typeof(object[])); iLGenerator.DeclareLocal(typeof(object[])); iLGenerator.DeclareLocal(typeof(int[])); if (returnType != typeof(void)) { iLGenerator.DeclareLocal(returnType); } else { iLGenerator.DeclareLocal(typeof(object)); } iLGenerator.Emit(OpCodes.Ldc_I4, array.Length); iLGenerator.Emit(OpCodes.Newarr, typeof(object)); iLGenerator.Emit(OpCodes.Stloc_0); iLGenerator.Emit(OpCodes.Ldc_I4, array.Length - num); iLGenerator.Emit(OpCodes.Newarr, typeof(object)); iLGenerator.Emit(OpCodes.Stloc_1); iLGenerator.Emit(OpCodes.Ldc_I4, num2); iLGenerator.Emit(OpCodes.Newarr, typeof(int)); iLGenerator.Emit(OpCodes.Stloc_2); int j = 0; int num3 = 0; int num4 = 0; for (; j < array.Length; j++) { iLGenerator.Emit(OpCodes.Ldloc_0); iLGenerator.Emit(OpCodes.Ldc_I4, j); iLGenerator.Emit(OpCodes.Ldarg, j + 1); if (array[j].IsByRef) { if (array[j].GetElementType().IsValueType) { iLGenerator.Emit(OpCodes.Ldobj, array[j].GetElementType()); iLGenerator.Emit(OpCodes.Box, array[j].GetElementType()); } else { iLGenerator.Emit(OpCodes.Ldind_Ref); } } else if (array[j].IsValueType) { iLGenerator.Emit(OpCodes.Box, array[j]); } iLGenerator.Emit(OpCodes.Stelem_Ref); if (array[j].IsByRef) { iLGenerator.Emit(OpCodes.Ldloc_2); iLGenerator.Emit(OpCodes.Ldc_I4, num4); iLGenerator.Emit(OpCodes.Ldc_I4, j); iLGenerator.Emit(OpCodes.Stelem_I4); array2[num4] = j; num4++; } if (!parameters[j].IsIn && parameters[j].IsOut) { continue; } iLGenerator.Emit(OpCodes.Ldloc_1); iLGenerator.Emit(OpCodes.Ldc_I4, num3); iLGenerator.Emit(OpCodes.Ldarg, j + 1); if (array[j].IsByRef) { if (array[j].GetElementType().IsValueType) { iLGenerator.Emit(OpCodes.Ldobj, array[j].GetElementType()); iLGenerator.Emit(OpCodes.Box, array[j].GetElementType()); } else { iLGenerator.Emit(OpCodes.Ldind_Ref); } } else if (array[j].IsValueType) { iLGenerator.Emit(OpCodes.Box, array[j]); } iLGenerator.Emit(OpCodes.Stelem_Ref); num3++; } iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldloc_0); iLGenerator.Emit(OpCodes.Ldloc_1); iLGenerator.Emit(OpCodes.Ldloc_2); MethodInfo method2 = delegateParent.GetMethod("callFunction"); iLGenerator.Emit(OpCodes.Call, method2); if (returnType == typeof(void)) { iLGenerator.Emit(OpCodes.Pop); iLGenerator.Emit(OpCodes.Ldnull); } else if (returnType.IsValueType) { iLGenerator.Emit(OpCodes.Unbox, returnType); iLGenerator.Emit(OpCodes.Ldobj, returnType); } else { iLGenerator.Emit(OpCodes.Castclass, returnType); } iLGenerator.Emit(OpCodes.Stloc_3); for (int k = 0; k < array2.Length; k++) { iLGenerator.Emit(OpCodes.Ldarg, array2[k] + 1); iLGenerator.Emit(OpCodes.Ldloc_0); iLGenerator.Emit(OpCodes.Ldc_I4, array2[k]); iLGenerator.Emit(OpCodes.Ldelem_Ref); if (array[array2[k]].GetElementType().IsValueType) { iLGenerator.Emit(OpCodes.Unbox, array[array2[k]].GetElementType()); iLGenerator.Emit(OpCodes.Ldobj, array[array2[k]].GetElementType()); iLGenerator.Emit(OpCodes.Stobj, array[array2[k]].GetElementType()); } else { iLGenerator.Emit(OpCodes.Castclass, array[array2[k]].GetElementType()); iLGenerator.Emit(OpCodes.Stind_Ref); } } if (returnType != typeof(void)) { iLGenerator.Emit(OpCodes.Ldloc_3); } iLGenerator.Emit(OpCodes.Ret); return typeBuilder.CreateType(); } public void GenerateClass(Type klass, out Type newType, out Type[][] returnTypes, LuaTable luaTable) { string name; lock (this) { name = "LuaGeneratedClass" + luaClassNumber; luaClassNumber++; } TypeBuilder typeBuilder = ((!klass.IsInterface) ? newModule.DefineType(name, TypeAttributes.Public, klass, new Type[1] { typeof(ILuaGeneratedType) }) : newModule.DefineType(name, TypeAttributes.Public, typeof(object), new Type[2] { klass, typeof(ILuaGeneratedType) })); FieldBuilder fieldBuilder = typeBuilder.DefineField("__luaInterface_luaTable", typeof(LuaTable), FieldAttributes.Public); FieldBuilder fieldBuilder2 = typeBuilder.DefineField("__luaInterface_returnTypes", typeof(Type[][]), FieldAttributes.Public); ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[2] { typeof(LuaTable), typeof(Type[][]) }); ILGenerator iLGenerator = constructorBuilder.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); if (klass.IsInterface) { iLGenerator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); } else { iLGenerator.Emit(OpCodes.Call, klass.GetConstructor(Type.EmptyTypes)); } iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Stfld, fieldBuilder); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldarg_2); iLGenerator.Emit(OpCodes.Stfld, fieldBuilder2); iLGenerator.Emit(OpCodes.Ret); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; MethodInfo[] methods = klass.GetMethods(bindingAttr); returnTypes = new Type[methods.Length][]; int num = 0; MethodInfo[] array = methods; foreach (MethodInfo methodInfo in array) { if (klass.IsInterface) { GenerateMethod(typeBuilder, methodInfo, MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask, num, fieldBuilder, fieldBuilder2, false, out returnTypes[num]); num++; } else if (!methodInfo.IsPrivate && !methodInfo.IsFinal && methodInfo.IsVirtual && luaTable[methodInfo.Name] != null) { GenerateMethod(typeBuilder, methodInfo, (methodInfo.Attributes | MethodAttributes.VtableLayoutMask) ^ MethodAttributes.VtableLayoutMask, num, fieldBuilder, fieldBuilder2, true, out returnTypes[num]); num++; } } MethodBuilder methodBuilder = typeBuilder.DefineMethod("__luaInterface_getLuaTable", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, typeof(LuaTable), new Type[0]); typeBuilder.DefineMethodOverride(methodBuilder, typeof(ILuaGeneratedType).GetMethod("__luaInterface_getLuaTable")); iLGenerator = methodBuilder.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, fieldBuilder); iLGenerator.Emit(OpCodes.Ret); newType = typeBuilder.CreateType(); } private void GenerateMethod(TypeBuilder myType, MethodInfo method, MethodAttributes attributes, int methodIndex, FieldInfo luaTableField, FieldInfo returnTypesField, bool generateBase, out Type[] returnTypes) { ParameterInfo[] parameters = method.GetParameters(); Type[] array = new Type[parameters.Length]; List list = new List(); int num = 0; int num2 = 0; Type returnType = method.ReturnType; list.Add(returnType); for (int i = 0; i < array.Length; i++) { array[i] = parameters[i].ParameterType; if (!parameters[i].IsIn && parameters[i].IsOut) { num++; } if (array[i].IsByRef) { list.Add(array[i].GetElementType()); num2++; } } int[] array2 = new int[num2]; returnTypes = list.ToArray(); if (generateBase) { string name = "__luaInterface_base_" + method.Name; MethodBuilder methodBuilder = myType.DefineMethod(name, MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask, returnType, array); ILGenerator iLGenerator = methodBuilder.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); for (int j = 0; j < array.Length; j++) { iLGenerator.Emit(OpCodes.Ldarg, j + 1); } iLGenerator.Emit(OpCodes.Call, method); iLGenerator.Emit(OpCodes.Ret); } MethodBuilder methodBuilder2 = myType.DefineMethod(method.Name, attributes, returnType, array); if (myType.BaseType.Equals(typeof(object))) { myType.DefineMethodOverride(methodBuilder2, method); } ILGenerator iLGenerator2 = methodBuilder2.GetILGenerator(); iLGenerator2.DeclareLocal(typeof(object[])); iLGenerator2.DeclareLocal(typeof(object[])); iLGenerator2.DeclareLocal(typeof(int[])); if (returnType != typeof(void)) { iLGenerator2.DeclareLocal(returnType); } else { iLGenerator2.DeclareLocal(typeof(object)); } iLGenerator2.Emit(OpCodes.Ldc_I4, array.Length); iLGenerator2.Emit(OpCodes.Newarr, typeof(object)); iLGenerator2.Emit(OpCodes.Stloc_0); iLGenerator2.Emit(OpCodes.Ldc_I4, array.Length - num + 1); iLGenerator2.Emit(OpCodes.Newarr, typeof(object)); iLGenerator2.Emit(OpCodes.Stloc_1); iLGenerator2.Emit(OpCodes.Ldc_I4, num2); iLGenerator2.Emit(OpCodes.Newarr, typeof(int)); iLGenerator2.Emit(OpCodes.Stloc_2); iLGenerator2.Emit(OpCodes.Ldloc_1); iLGenerator2.Emit(OpCodes.Ldc_I4_0); iLGenerator2.Emit(OpCodes.Ldarg_0); iLGenerator2.Emit(OpCodes.Ldfld, luaTableField); iLGenerator2.Emit(OpCodes.Stelem_Ref); int k = 0; int num3 = 1; int num4 = 0; for (; k < array.Length; k++) { iLGenerator2.Emit(OpCodes.Ldloc_0); iLGenerator2.Emit(OpCodes.Ldc_I4, k); iLGenerator2.Emit(OpCodes.Ldarg, k + 1); if (array[k].IsByRef) { if (array[k].GetElementType().IsValueType) { iLGenerator2.Emit(OpCodes.Ldobj, array[k].GetElementType()); iLGenerator2.Emit(OpCodes.Box, array[k].GetElementType()); } else { iLGenerator2.Emit(OpCodes.Ldind_Ref); } } else if (array[k].IsValueType) { iLGenerator2.Emit(OpCodes.Box, array[k]); } iLGenerator2.Emit(OpCodes.Stelem_Ref); if (array[k].IsByRef) { iLGenerator2.Emit(OpCodes.Ldloc_2); iLGenerator2.Emit(OpCodes.Ldc_I4, num4); iLGenerator2.Emit(OpCodes.Ldc_I4, k); iLGenerator2.Emit(OpCodes.Stelem_I4); array2[num4] = k; num4++; } if (!parameters[k].IsIn && parameters[k].IsOut) { continue; } iLGenerator2.Emit(OpCodes.Ldloc_1); iLGenerator2.Emit(OpCodes.Ldc_I4, num3); iLGenerator2.Emit(OpCodes.Ldarg, k + 1); if (array[k].IsByRef) { if (array[k].GetElementType().IsValueType) { iLGenerator2.Emit(OpCodes.Ldobj, array[k].GetElementType()); iLGenerator2.Emit(OpCodes.Box, array[k].GetElementType()); } else { iLGenerator2.Emit(OpCodes.Ldind_Ref); } } else if (array[k].IsValueType) { iLGenerator2.Emit(OpCodes.Box, array[k]); } iLGenerator2.Emit(OpCodes.Stelem_Ref); num3++; } iLGenerator2.Emit(OpCodes.Ldarg_0); iLGenerator2.Emit(OpCodes.Ldfld, luaTableField); iLGenerator2.Emit(OpCodes.Ldstr, method.Name); iLGenerator2.Emit(OpCodes.Call, classHelper.GetMethod("getTableFunction")); Label label = iLGenerator2.DefineLabel(); iLGenerator2.Emit(OpCodes.Dup); iLGenerator2.Emit(OpCodes.Brtrue_S, label); iLGenerator2.Emit(OpCodes.Pop); if (!method.IsAbstract) { iLGenerator2.Emit(OpCodes.Ldarg_0); for (int l = 0; l < array.Length; l++) { iLGenerator2.Emit(OpCodes.Ldarg, l + 1); } iLGenerator2.Emit(OpCodes.Call, method); if (returnType == typeof(void)) { iLGenerator2.Emit(OpCodes.Pop); } iLGenerator2.Emit(OpCodes.Ret); iLGenerator2.Emit(OpCodes.Ldnull); } else { iLGenerator2.Emit(OpCodes.Ldnull); } Label label2 = iLGenerator2.DefineLabel(); iLGenerator2.Emit(OpCodes.Br_S, label2); iLGenerator2.MarkLabel(label); iLGenerator2.Emit(OpCodes.Ldloc_0); iLGenerator2.Emit(OpCodes.Ldarg_0); iLGenerator2.Emit(OpCodes.Ldfld, returnTypesField); iLGenerator2.Emit(OpCodes.Ldc_I4, methodIndex); iLGenerator2.Emit(OpCodes.Ldelem_Ref); iLGenerator2.Emit(OpCodes.Ldloc_1); iLGenerator2.Emit(OpCodes.Ldloc_2); iLGenerator2.Emit(OpCodes.Call, classHelper.GetMethod("callFunction")); iLGenerator2.MarkLabel(label2); if (returnType == typeof(void)) { iLGenerator2.Emit(OpCodes.Pop); iLGenerator2.Emit(OpCodes.Ldnull); } else if (returnType.IsValueType) { iLGenerator2.Emit(OpCodes.Unbox, returnType); iLGenerator2.Emit(OpCodes.Ldobj, returnType); } else { iLGenerator2.Emit(OpCodes.Castclass, returnType); } iLGenerator2.Emit(OpCodes.Stloc_3); for (int m = 0; m < array2.Length; m++) { iLGenerator2.Emit(OpCodes.Ldarg, array2[m] + 1); iLGenerator2.Emit(OpCodes.Ldloc_0); iLGenerator2.Emit(OpCodes.Ldc_I4, array2[m]); iLGenerator2.Emit(OpCodes.Ldelem_Ref); if (array[array2[m]].GetElementType().IsValueType) { iLGenerator2.Emit(OpCodes.Unbox, array[array2[m]].GetElementType()); iLGenerator2.Emit(OpCodes.Ldobj, array[array2[m]].GetElementType()); iLGenerator2.Emit(OpCodes.Stobj, array[array2[m]].GetElementType()); } else { iLGenerator2.Emit(OpCodes.Castclass, array[array2[m]].GetElementType()); iLGenerator2.Emit(OpCodes.Stind_Ref); } } if (returnType != typeof(void)) { iLGenerator2.Emit(OpCodes.Ldloc_3); } iLGenerator2.Emit(OpCodes.Ret); } public LuaEventHandler GetEvent(Type eventHandlerType, LuaFunction eventHandler) { Type type; if (eventHandlerCollection.ContainsKey(eventHandlerType)) { type = eventHandlerCollection[eventHandlerType]; } else { type = GenerateEvent(eventHandlerType); eventHandlerCollection[eventHandlerType] = type; } LuaEventHandler luaEventHandler = (LuaEventHandler)Activator.CreateInstance(type); luaEventHandler.handler = eventHandler; return luaEventHandler; } public Delegate GetDelegate(Type delegateType, LuaFunction luaFunc) { List list = new List(); Type type; if (delegateCollection.ContainsKey(delegateType)) { type = delegateCollection[delegateType]; } else { type = GenerateDelegate(delegateType); delegateCollection[delegateType] = type; } MethodInfo method = delegateType.GetMethod("Invoke"); list.Add(method.ReturnType); ParameterInfo[] parameters = method.GetParameters(); foreach (ParameterInfo parameterInfo in parameters) { if (parameterInfo.ParameterType.IsByRef) { list.Add(parameterInfo.ParameterType); } } LuaDelegate luaDelegate = (LuaDelegate)Activator.CreateInstance(type); luaDelegate.function = luaFunc; luaDelegate.returnTypes = list.ToArray(); return Delegate.CreateDelegate(delegateType, luaDelegate, "CallFunction"); } public object GetClassInstance(Type klass, LuaTable luaTable) { LuaClassType value; if (classCollection.ContainsKey(klass)) { value = classCollection[klass]; } else { value = default(LuaClassType); GenerateClass(klass, out value.klass, out value.returnTypes, luaTable); classCollection[klass] = value; } return Activator.CreateInstance(value.klass, luaTable, value.returnTypes); } } }