GenerateEventAssembly.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using System.Reflection.Emit;
  6. using System.Threading;
  7. namespace LuaInterface
  8. {
  9. /*
  10. * Structure to store a type and the return types of
  11. * its methods (the type of the returned value and out/ref
  12. * parameters).
  13. */
  14. struct LuaClassType
  15. {
  16. public Type klass;
  17. public Type[][] returnTypes;
  18. }
  19. /*
  20. * Common interface for types generated from tables. The method
  21. * returns the table that overrides some or all of the type's methods.
  22. */
  23. public interface ILuaGeneratedType
  24. {
  25. LuaTable __luaInterface_getLuaTable();
  26. }
  27. /*
  28. * Class used for generating delegates that get a function from the Lua
  29. * stack as a delegate of a specific type.
  30. *
  31. * Author: Fabio Mascarenhas
  32. * Version: 1.0
  33. */
  34. class DelegateGenerator
  35. {
  36. private ObjectTranslator translator;
  37. private Type delegateType;
  38. public DelegateGenerator(ObjectTranslator translator,Type delegateType)
  39. {
  40. this.translator=translator;
  41. this.delegateType=delegateType;
  42. }
  43. public object extractGenerated(IntPtr luaState,int stackPos)
  44. {
  45. return CodeGeneration.Instance.GetDelegate(delegateType,translator.getFunction(luaState,stackPos));
  46. }
  47. }
  48. /*
  49. * Class used for generating delegates that get a table from the Lua
  50. * stack as a an object of a specific type.
  51. *
  52. * Author: Fabio Mascarenhas
  53. * Version: 1.0
  54. */
  55. class ClassGenerator
  56. {
  57. private ObjectTranslator translator;
  58. private Type klass;
  59. public ClassGenerator(ObjectTranslator translator,Type klass)
  60. {
  61. this.translator=translator;
  62. this.klass=klass;
  63. }
  64. public object extractGenerated(IntPtr luaState,int stackPos)
  65. {
  66. return CodeGeneration.Instance.GetClassInstance(klass,translator.getTable(luaState,stackPos));
  67. }
  68. }
  69. /*
  70. * Dynamically generates new types from existing types and
  71. * Lua function and table values. Generated types are event handlers,
  72. * delegates, interface implementations and subclasses.
  73. *
  74. * Author: Fabio Mascarenhas
  75. * Version: 1.0
  76. */
  77. class CodeGeneration
  78. {
  79. private Type eventHandlerParent=typeof(LuaEventHandler);
  80. private Dictionary<Type, Type> eventHandlerCollection=new Dictionary<Type, Type>();
  81. private Type delegateParent=typeof(LuaDelegate);
  82. private Dictionary<Type, Type> delegateCollection=new Dictionary<Type, Type>();
  83. private Type classHelper=typeof(LuaClassHelper);
  84. private Dictionary<Type, LuaClassType> classCollection=new Dictionary<Type, LuaClassType>();
  85. private AssemblyName assemblyName;
  86. private AssemblyBuilder newAssembly;
  87. private ModuleBuilder newModule;
  88. private int luaClassNumber=1;
  89. private static readonly CodeGeneration instance = new CodeGeneration();
  90. static CodeGeneration()
  91. {
  92. }
  93. private CodeGeneration()
  94. {
  95. // Create an assembly name
  96. assemblyName=new AssemblyName( );
  97. assemblyName.Name="LuaInterface_generatedcode";
  98. // Create a new assembly with one module.
  99. newAssembly=Thread.GetDomain().DefineDynamicAssembly(
  100. assemblyName, AssemblyBuilderAccess.Run);
  101. newModule=newAssembly.DefineDynamicModule("LuaInterface_generatedcode");
  102. }
  103. /*
  104. * Singleton instance of the class
  105. */
  106. public static CodeGeneration Instance
  107. {
  108. get
  109. {
  110. return instance;
  111. }
  112. }
  113. /*
  114. * Generates an event handler that calls a Lua function
  115. */
  116. private Type GenerateEvent(Type eventHandlerType)
  117. {
  118. string typeName;
  119. lock(this)
  120. {
  121. typeName = "LuaGeneratedClass" + luaClassNumber;
  122. luaClassNumber++;
  123. }
  124. // Define a public class in the assembly, called typeName
  125. TypeBuilder myType=newModule.DefineType(typeName,TypeAttributes.Public,eventHandlerParent);
  126. // Defines the handler method. Its signature is void(object,<subclassofEventArgs>)
  127. Type[] paramTypes = new Type[2];
  128. paramTypes[0]=typeof(object);
  129. paramTypes[1]=eventHandlerType;
  130. Type returnType=typeof(void);
  131. MethodBuilder handleMethod=myType.DefineMethod("HandleEvent",
  132. MethodAttributes.Public|MethodAttributes.HideBySig,
  133. returnType,paramTypes);
  134. // Emits the IL for the method. It loads the arguments
  135. // and calls the handleEvent method of the base class
  136. ILGenerator generator=handleMethod.GetILGenerator( );
  137. generator.Emit(OpCodes.Ldarg_0);
  138. generator.Emit(OpCodes.Ldarg_1);
  139. generator.Emit(OpCodes.Ldarg_2);
  140. MethodInfo miGenericEventHandler;
  141. miGenericEventHandler=eventHandlerParent.GetMethod("handleEvent");
  142. generator.Emit(OpCodes.Call,miGenericEventHandler);
  143. // returns
  144. generator.Emit(OpCodes.Ret);
  145. // creates the new type
  146. return myType.CreateType();
  147. }
  148. /*
  149. * Generates a type that can be used for instantiating a delegate
  150. * of the provided type, given a Lua function.
  151. */
  152. private Type GenerateDelegate(Type delegateType)
  153. {
  154. string typeName;
  155. lock(this)
  156. {
  157. typeName = "LuaGeneratedClass" + luaClassNumber;
  158. luaClassNumber++;
  159. }
  160. // Define a public class in the assembly, called typeName
  161. TypeBuilder myType=newModule.DefineType(typeName,TypeAttributes.Public,delegateParent);
  162. // Defines the delegate method with the same signature as the
  163. // Invoke method of delegateType
  164. MethodInfo invokeMethod=delegateType.GetMethod("Invoke");
  165. ParameterInfo[] paramInfo=invokeMethod.GetParameters();
  166. Type[] paramTypes=new Type[paramInfo.Length];
  167. Type returnType=invokeMethod.ReturnType;
  168. // Counts out and ref params, for use later
  169. int nOutParams=0; int nOutAndRefParams=0;
  170. for(int i=0;i<paramTypes.Length;i++)
  171. {
  172. paramTypes[i]=paramInfo[i].ParameterType;
  173. if((!paramInfo[i].IsIn) && paramInfo[i].IsOut)
  174. nOutParams++;
  175. if(paramTypes[i].IsByRef)
  176. nOutAndRefParams++;
  177. }
  178. int[] refArgs=new int[nOutAndRefParams];
  179. MethodBuilder delegateMethod=myType.DefineMethod("CallFunction",
  180. invokeMethod.Attributes,
  181. returnType,paramTypes);
  182. // Generates the IL for the method
  183. ILGenerator generator=delegateMethod.GetILGenerator( );
  184. generator.DeclareLocal(typeof(object[])); // original arguments
  185. generator.DeclareLocal(typeof(object[])); // with out-only arguments removed
  186. generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments
  187. if(!(returnType == typeof(void))) // return value
  188. generator.DeclareLocal(returnType);
  189. else
  190. generator.DeclareLocal(typeof(object));
  191. // Initializes local variables
  192. generator.Emit(OpCodes.Ldc_I4,paramTypes.Length);
  193. generator.Emit(OpCodes.Newarr,typeof(object));
  194. generator.Emit(OpCodes.Stloc_0);
  195. generator.Emit(OpCodes.Ldc_I4,paramTypes.Length-nOutParams);
  196. generator.Emit(OpCodes.Newarr,typeof(object));
  197. generator.Emit(OpCodes.Stloc_1);
  198. generator.Emit(OpCodes.Ldc_I4,nOutAndRefParams);
  199. generator.Emit(OpCodes.Newarr,typeof(int));
  200. generator.Emit(OpCodes.Stloc_2);
  201. // Stores the arguments in the local variables
  202. for(int iArgs=0,iInArgs=0,iOutArgs=0;iArgs<paramTypes.Length;iArgs++)
  203. {
  204. generator.Emit(OpCodes.Ldloc_0);
  205. generator.Emit(OpCodes.Ldc_I4,iArgs);
  206. generator.Emit(OpCodes.Ldarg,iArgs+1);
  207. if(paramTypes[iArgs].IsByRef)
  208. {
  209. if(paramTypes[iArgs].GetElementType().IsValueType)
  210. {
  211. generator.Emit(OpCodes.Ldobj,paramTypes[iArgs].GetElementType());
  212. generator.Emit(OpCodes.Box,paramTypes[iArgs].GetElementType());
  213. } else generator.Emit(OpCodes.Ldind_Ref);
  214. }
  215. else
  216. {
  217. if(paramTypes[iArgs].IsValueType)
  218. generator.Emit(OpCodes.Box,paramTypes[iArgs]);
  219. }
  220. generator.Emit(OpCodes.Stelem_Ref);
  221. if(paramTypes[iArgs].IsByRef)
  222. {
  223. generator.Emit(OpCodes.Ldloc_2);
  224. generator.Emit(OpCodes.Ldc_I4,iOutArgs);
  225. generator.Emit(OpCodes.Ldc_I4,iArgs);
  226. generator.Emit(OpCodes.Stelem_I4);
  227. refArgs[iOutArgs]=iArgs;
  228. iOutArgs++;
  229. }
  230. if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut))
  231. {
  232. generator.Emit(OpCodes.Ldloc_1);
  233. generator.Emit(OpCodes.Ldc_I4,iInArgs);
  234. generator.Emit(OpCodes.Ldarg,iArgs+1);
  235. if(paramTypes[iArgs].IsByRef)
  236. {
  237. if(paramTypes[iArgs].GetElementType().IsValueType)
  238. {
  239. generator.Emit(OpCodes.Ldobj,paramTypes[iArgs].GetElementType());
  240. generator.Emit(OpCodes.Box,paramTypes[iArgs].GetElementType());
  241. }
  242. else generator.Emit(OpCodes.Ldind_Ref);
  243. }
  244. else
  245. {
  246. if(paramTypes[iArgs].IsValueType)
  247. generator.Emit(OpCodes.Box,paramTypes[iArgs]);
  248. }
  249. generator.Emit(OpCodes.Stelem_Ref);
  250. iInArgs++;
  251. }
  252. }
  253. // Calls the callFunction method of the base class
  254. generator.Emit(OpCodes.Ldarg_0);
  255. generator.Emit(OpCodes.Ldloc_0);
  256. generator.Emit(OpCodes.Ldloc_1);
  257. generator.Emit(OpCodes.Ldloc_2);
  258. MethodInfo miGenericEventHandler;
  259. miGenericEventHandler=delegateParent.GetMethod("callFunction");
  260. generator.Emit(OpCodes.Call,miGenericEventHandler);
  261. // Stores return value
  262. if(returnType == typeof(void))
  263. {
  264. generator.Emit(OpCodes.Pop);
  265. generator.Emit(OpCodes.Ldnull);
  266. }
  267. else if(returnType.IsValueType)
  268. {
  269. generator.Emit(OpCodes.Unbox,returnType);
  270. generator.Emit(OpCodes.Ldobj,returnType);
  271. } else generator.Emit(OpCodes.Castclass,returnType);
  272. generator.Emit(OpCodes.Stloc_3);
  273. // Stores new value of out and ref params
  274. for(int i=0;i<refArgs.Length;i++)
  275. {
  276. generator.Emit(OpCodes.Ldarg,refArgs[i]+1);
  277. generator.Emit(OpCodes.Ldloc_0);
  278. generator.Emit(OpCodes.Ldc_I4,refArgs[i]);
  279. generator.Emit(OpCodes.Ldelem_Ref);
  280. if(paramTypes[refArgs[i]].GetElementType().IsValueType)
  281. {
  282. generator.Emit(OpCodes.Unbox,paramTypes[refArgs[i]].GetElementType());
  283. generator.Emit(OpCodes.Ldobj,paramTypes[refArgs[i]].GetElementType());
  284. generator.Emit(OpCodes.Stobj,paramTypes[refArgs[i]].GetElementType());
  285. }
  286. else
  287. {
  288. generator.Emit(OpCodes.Castclass,paramTypes[refArgs[i]].GetElementType());
  289. generator.Emit(OpCodes.Stind_Ref);
  290. }
  291. }
  292. // Returns
  293. if(!(returnType == typeof(void)))
  294. generator.Emit(OpCodes.Ldloc_3);
  295. generator.Emit(OpCodes.Ret);
  296. // creates the new type
  297. return myType.CreateType();
  298. }
  299. /*
  300. * Generates an implementation of klass, if it is an interface, or
  301. * a subclass of klass that delegates its virtual methods to a Lua table.
  302. */
  303. public void GenerateClass(Type klass,out Type newType,out Type[][] returnTypes, LuaTable luaTable)
  304. {
  305. string typeName;
  306. lock(this)
  307. {
  308. typeName = "LuaGeneratedClass" + luaClassNumber;
  309. luaClassNumber++;
  310. }
  311. TypeBuilder myType;
  312. // Define a public class in the assembly, called typeName
  313. if(klass.IsInterface)
  314. myType=newModule.DefineType(typeName,TypeAttributes.Public,typeof(object),new Type[] { klass,typeof(ILuaGeneratedType) });
  315. else
  316. myType=newModule.DefineType(typeName,TypeAttributes.Public,klass,new Type[] { typeof(ILuaGeneratedType) });
  317. // Field that stores the Lua table
  318. FieldBuilder luaTableField=myType.DefineField("__luaInterface_luaTable",typeof(LuaTable),FieldAttributes.Public);
  319. // Field that stores the return types array
  320. FieldBuilder returnTypesField=myType.DefineField("__luaInterface_returnTypes",typeof(Type[][]),FieldAttributes.Public);
  321. // Generates the constructor for the new type, it takes a Lua table and an array
  322. // of return types and stores them in the respective fields
  323. ConstructorBuilder constructor=
  324. myType.DefineConstructor(MethodAttributes.Public,CallingConventions.Standard,new Type[] { typeof(LuaTable),typeof(Type[][]) });
  325. ILGenerator generator=constructor.GetILGenerator();
  326. generator.Emit(OpCodes.Ldarg_0);
  327. if(klass.IsInterface)
  328. generator.Emit(OpCodes.Call,typeof(object).GetConstructor(Type.EmptyTypes));
  329. else
  330. generator.Emit(OpCodes.Call,klass.GetConstructor(Type.EmptyTypes));
  331. generator.Emit(OpCodes.Ldarg_0);
  332. generator.Emit(OpCodes.Ldarg_1);
  333. generator.Emit(OpCodes.Stfld,luaTableField);
  334. generator.Emit(OpCodes.Ldarg_0);
  335. generator.Emit(OpCodes.Ldarg_2);
  336. generator.Emit(OpCodes.Stfld,returnTypesField);
  337. generator.Emit(OpCodes.Ret);
  338. // Generates overriden versions of the klass' public and protected virtual methods that have been explicitly specfied
  339. BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
  340. MethodInfo[] classMethods=klass.GetMethods(flags);
  341. returnTypes=new Type[classMethods.Length][];
  342. int i=0;
  343. foreach(MethodInfo method in classMethods)
  344. {
  345. if(klass.IsInterface)
  346. {
  347. GenerateMethod(myType,method,
  348. MethodAttributes.HideBySig|MethodAttributes.Virtual|MethodAttributes.NewSlot,
  349. i,luaTableField,returnTypesField,false,out returnTypes[i]);
  350. i++;
  351. }
  352. else
  353. {
  354. if(!method.IsPrivate && !method.IsFinal && method.IsVirtual)
  355. {
  356. if (luaTable[method.Name] != null) {
  357. GenerateMethod(myType,method,(method.Attributes|MethodAttributes.NewSlot)^MethodAttributes.NewSlot,i,
  358. luaTableField,returnTypesField,true,out returnTypes[i]);
  359. i++;
  360. }
  361. }
  362. }
  363. }
  364. // Generates an implementation of the __luaInterface_getLuaTable method
  365. MethodBuilder returnTableMethod=myType.DefineMethod("__luaInterface_getLuaTable",
  366. MethodAttributes.Public|MethodAttributes.HideBySig|MethodAttributes.Virtual,
  367. typeof(LuaTable),new Type[0]);
  368. myType.DefineMethodOverride(returnTableMethod,typeof(ILuaGeneratedType).GetMethod("__luaInterface_getLuaTable"));
  369. generator=returnTableMethod.GetILGenerator();
  370. generator.Emit(OpCodes.Ldarg_0);
  371. generator.Emit(OpCodes.Ldfld,luaTableField);
  372. generator.Emit(OpCodes.Ret);
  373. // Creates the type
  374. newType=myType.CreateType();
  375. }
  376. /*
  377. * Generates an overriden implementation of method inside myType that delegates
  378. * to a function in a Lua table with the same name, if the function exists. If it
  379. * doesn't the method calls the base method (or does nothing, in case of interface
  380. * implementations).
  381. */
  382. private void GenerateMethod(TypeBuilder myType,MethodInfo method,MethodAttributes attributes,
  383. int methodIndex,FieldInfo luaTableField,FieldInfo returnTypesField,bool generateBase,out Type[] returnTypes)
  384. {
  385. ParameterInfo[] paramInfo=method.GetParameters();
  386. Type[] paramTypes=new Type[paramInfo.Length];
  387. List<Type> returnTypesList=new List<Type>();
  388. // Counts out and ref parameters, for later use,
  389. // and creates the list of return types
  390. int nOutParams=0; int nOutAndRefParams=0;
  391. Type returnType=method.ReturnType;
  392. returnTypesList.Add(returnType);
  393. for(int i=0;i<paramTypes.Length;i++)
  394. {
  395. paramTypes[i]=paramInfo[i].ParameterType;
  396. if((!paramInfo[i].IsIn) && paramInfo[i].IsOut)
  397. nOutParams++;
  398. if(paramTypes[i].IsByRef)
  399. {
  400. returnTypesList.Add(paramTypes[i].GetElementType());
  401. nOutAndRefParams++;
  402. }
  403. }
  404. int[] refArgs=new int[nOutAndRefParams];
  405. returnTypes=returnTypesList.ToArray();
  406. // Generates a version of the method that calls the base implementation
  407. // directly, for use by the base field of the table
  408. if(generateBase)
  409. {
  410. String baseName = "__luaInterface_base_"+method.Name;
  411. MethodBuilder baseMethod=myType.DefineMethod(baseName,
  412. MethodAttributes.Public|MethodAttributes.NewSlot|MethodAttributes.HideBySig,
  413. returnType,paramTypes);
  414. ILGenerator generatorBase=baseMethod.GetILGenerator();
  415. generatorBase.Emit(OpCodes.Ldarg_0);
  416. for(int i=0;i<paramTypes.Length;i++)
  417. generatorBase.Emit(OpCodes.Ldarg,i+1);
  418. generatorBase.Emit(OpCodes.Call,method);
  419. //if (returnType == typeof(void))
  420. // generatorBase.Emit(OpCodes.Pop);
  421. generatorBase.Emit(OpCodes.Ret);
  422. }
  423. // Defines the method
  424. MethodBuilder methodImpl=myType.DefineMethod(method.Name,attributes,
  425. returnType,paramTypes);
  426. // If it's an implementation of an interface tells what method it
  427. // is overriding
  428. if(myType.BaseType.Equals(typeof(object)))
  429. myType.DefineMethodOverride(methodImpl,method);
  430. ILGenerator generator=methodImpl.GetILGenerator( );
  431. generator.DeclareLocal(typeof(object[])); // original arguments
  432. generator.DeclareLocal(typeof(object[])); // with out-only arguments removed
  433. generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments
  434. if(!(returnType == typeof(void))) // return value
  435. generator.DeclareLocal(returnType);
  436. else
  437. generator.DeclareLocal(typeof(object));
  438. // Initializes local variables
  439. generator.Emit(OpCodes.Ldc_I4,paramTypes.Length);
  440. generator.Emit(OpCodes.Newarr,typeof(object));
  441. generator.Emit(OpCodes.Stloc_0);
  442. generator.Emit(OpCodes.Ldc_I4,paramTypes.Length-nOutParams+1);
  443. generator.Emit(OpCodes.Newarr,typeof(object));
  444. generator.Emit(OpCodes.Stloc_1);
  445. generator.Emit(OpCodes.Ldc_I4,nOutAndRefParams);
  446. generator.Emit(OpCodes.Newarr,typeof(int));
  447. generator.Emit(OpCodes.Stloc_2);
  448. generator.Emit(OpCodes.Ldloc_1);
  449. generator.Emit(OpCodes.Ldc_I4_0);
  450. generator.Emit(OpCodes.Ldarg_0);
  451. generator.Emit(OpCodes.Ldfld,luaTableField);
  452. generator.Emit(OpCodes.Stelem_Ref);
  453. // Stores the arguments into the local variables, as needed
  454. for(int iArgs=0,iInArgs=1,iOutArgs=0;iArgs<paramTypes.Length;iArgs++)
  455. {
  456. generator.Emit(OpCodes.Ldloc_0);
  457. generator.Emit(OpCodes.Ldc_I4,iArgs);
  458. generator.Emit(OpCodes.Ldarg,iArgs+1);
  459. if(paramTypes[iArgs].IsByRef)
  460. {
  461. if(paramTypes[iArgs].GetElementType().IsValueType)
  462. {
  463. generator.Emit(OpCodes.Ldobj,paramTypes[iArgs].GetElementType());
  464. generator.Emit(OpCodes.Box,paramTypes[iArgs].GetElementType());
  465. }
  466. else generator.Emit(OpCodes.Ldind_Ref);
  467. }
  468. else
  469. {
  470. if(paramTypes[iArgs].IsValueType)
  471. generator.Emit(OpCodes.Box,paramTypes[iArgs]);
  472. }
  473. generator.Emit(OpCodes.Stelem_Ref);
  474. if(paramTypes[iArgs].IsByRef)
  475. {
  476. generator.Emit(OpCodes.Ldloc_2);
  477. generator.Emit(OpCodes.Ldc_I4,iOutArgs);
  478. generator.Emit(OpCodes.Ldc_I4,iArgs);
  479. generator.Emit(OpCodes.Stelem_I4);
  480. refArgs[iOutArgs]=iArgs;
  481. iOutArgs++;
  482. }
  483. if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut))
  484. {
  485. generator.Emit(OpCodes.Ldloc_1);
  486. generator.Emit(OpCodes.Ldc_I4,iInArgs);
  487. generator.Emit(OpCodes.Ldarg,iArgs+1);
  488. if(paramTypes[iArgs].IsByRef)
  489. {
  490. if(paramTypes[iArgs].GetElementType().IsValueType)
  491. {
  492. generator.Emit(OpCodes.Ldobj,paramTypes[iArgs].GetElementType());
  493. generator.Emit(OpCodes.Box,paramTypes[iArgs].GetElementType());
  494. }
  495. else generator.Emit(OpCodes.Ldind_Ref);
  496. }
  497. else
  498. {
  499. if(paramTypes[iArgs].IsValueType)
  500. generator.Emit(OpCodes.Box,paramTypes[iArgs]);
  501. }
  502. generator.Emit(OpCodes.Stelem_Ref);
  503. iInArgs++;
  504. }
  505. }
  506. // Gets the function the method will delegate to by calling
  507. // the getTableFunction method of class LuaClassHelper
  508. generator.Emit(OpCodes.Ldarg_0);
  509. generator.Emit(OpCodes.Ldfld,luaTableField);
  510. generator.Emit(OpCodes.Ldstr,method.Name);
  511. generator.Emit(OpCodes.Call,classHelper.GetMethod("getTableFunction"));
  512. Label lab1=generator.DefineLabel();
  513. generator.Emit(OpCodes.Dup);
  514. generator.Emit(OpCodes.Brtrue_S,lab1);
  515. // Function does not exist, call base method
  516. generator.Emit(OpCodes.Pop);
  517. if(!method.IsAbstract)
  518. {
  519. generator.Emit(OpCodes.Ldarg_0);
  520. for(int i=0;i<paramTypes.Length;i++)
  521. generator.Emit(OpCodes.Ldarg,i+1);
  522. generator.Emit(OpCodes.Call,method);
  523. if(returnType == typeof(void))
  524. generator.Emit(OpCodes.Pop);
  525. generator.Emit(OpCodes.Ret);
  526. generator.Emit(OpCodes.Ldnull);
  527. } else
  528. generator.Emit(OpCodes.Ldnull);
  529. Label lab2=generator.DefineLabel();
  530. generator.Emit(OpCodes.Br_S,lab2);
  531. generator.MarkLabel(lab1);
  532. // Function exists, call using method callFunction of LuaClassHelper
  533. generator.Emit(OpCodes.Ldloc_0);
  534. generator.Emit(OpCodes.Ldarg_0);
  535. generator.Emit(OpCodes.Ldfld,returnTypesField);
  536. generator.Emit(OpCodes.Ldc_I4,methodIndex);
  537. generator.Emit(OpCodes.Ldelem_Ref);
  538. generator.Emit(OpCodes.Ldloc_1);
  539. generator.Emit(OpCodes.Ldloc_2);
  540. generator.Emit(OpCodes.Call,classHelper.GetMethod("callFunction"));
  541. generator.MarkLabel(lab2);
  542. // Stores the function return value
  543. if(returnType == typeof(void))
  544. {
  545. generator.Emit(OpCodes.Pop);
  546. generator.Emit(OpCodes.Ldnull);
  547. }
  548. else if(returnType.IsValueType)
  549. {
  550. generator.Emit(OpCodes.Unbox,returnType);
  551. generator.Emit(OpCodes.Ldobj,returnType);
  552. }
  553. else generator.Emit(OpCodes.Castclass,returnType);
  554. generator.Emit(OpCodes.Stloc_3);
  555. // Sets return values of out and ref parameters
  556. for(int i=0;i<refArgs.Length;i++)
  557. {
  558. generator.Emit(OpCodes.Ldarg,refArgs[i]+1);
  559. generator.Emit(OpCodes.Ldloc_0);
  560. generator.Emit(OpCodes.Ldc_I4,refArgs[i]);
  561. generator.Emit(OpCodes.Ldelem_Ref);
  562. if(paramTypes[refArgs[i]].GetElementType().IsValueType)
  563. {
  564. generator.Emit(OpCodes.Unbox,paramTypes[refArgs[i]].GetElementType());
  565. generator.Emit(OpCodes.Ldobj,paramTypes[refArgs[i]].GetElementType());
  566. generator.Emit(OpCodes.Stobj,paramTypes[refArgs[i]].GetElementType());
  567. }
  568. else
  569. {
  570. generator.Emit(OpCodes.Castclass,paramTypes[refArgs[i]].GetElementType());
  571. generator.Emit(OpCodes.Stind_Ref);
  572. }
  573. }
  574. // Returns
  575. if(!(returnType == typeof(void)))
  576. generator.Emit(OpCodes.Ldloc_3);
  577. generator.Emit(OpCodes.Ret);
  578. }
  579. /*
  580. * Gets an event handler for the event type that delegates to the eventHandler Lua function.
  581. * Caches the generated type.
  582. */
  583. public LuaEventHandler GetEvent(Type eventHandlerType, LuaFunction eventHandler)
  584. {
  585. Type eventConsumerType;
  586. if (eventHandlerCollection.ContainsKey(eventHandlerType))
  587. {
  588. eventConsumerType=eventHandlerCollection[eventHandlerType];
  589. }
  590. else
  591. {
  592. eventConsumerType=GenerateEvent(eventHandlerType);
  593. eventHandlerCollection[eventHandlerType] = eventConsumerType;
  594. }
  595. LuaEventHandler luaEventHandler=(LuaEventHandler)Activator.CreateInstance(eventConsumerType);
  596. luaEventHandler.handler=eventHandler;
  597. return luaEventHandler;
  598. }
  599. /*
  600. * Gets a delegate with delegateType that calls the luaFunc Lua function
  601. * Caches the generated type.
  602. */
  603. public Delegate GetDelegate(Type delegateType, LuaFunction luaFunc)
  604. {
  605. List<Type> returnTypes=new List<Type>();
  606. Type luaDelegateType;
  607. if (delegateCollection.ContainsKey(delegateType))
  608. {
  609. luaDelegateType=delegateCollection[delegateType];
  610. }
  611. else
  612. {
  613. luaDelegateType=GenerateDelegate(delegateType);
  614. delegateCollection[delegateType] = luaDelegateType;
  615. }
  616. MethodInfo methodInfo=delegateType.GetMethod("Invoke");
  617. returnTypes.Add(methodInfo.ReturnType);
  618. foreach(ParameterInfo paramInfo in methodInfo.GetParameters())
  619. if(paramInfo.ParameterType.IsByRef)
  620. returnTypes.Add(paramInfo.ParameterType);
  621. LuaDelegate luaDelegate=(LuaDelegate)Activator.CreateInstance(luaDelegateType);
  622. luaDelegate.function=luaFunc;
  623. luaDelegate.returnTypes=returnTypes.ToArray();
  624. return Delegate.CreateDelegate(delegateType,luaDelegate,"CallFunction");
  625. }
  626. /*
  627. * Gets an instance of an implementation of the klass interface or
  628. * subclass of klass that delegates public virtual methods to the
  629. * luaTable table.
  630. * Caches the generated type.
  631. */
  632. public object GetClassInstance(Type klass, LuaTable luaTable)
  633. {
  634. LuaClassType luaClassType;
  635. if (classCollection.ContainsKey(klass))
  636. {
  637. luaClassType=classCollection[klass];
  638. }
  639. else
  640. {
  641. luaClassType=new LuaClassType();
  642. GenerateClass(klass,out luaClassType.klass,out luaClassType.returnTypes,luaTable);
  643. classCollection[klass] = luaClassType;
  644. }
  645. return Activator.CreateInstance(luaClassType.klass,new object[] {luaTable,luaClassType.returnTypes});
  646. }
  647. }
  648. }