/trunk/Demo.Mmose.Core/LuaInterface/GenerateEventAssembly.cs

# · C# · 684 lines · 538 code · 37 blank · 109 comment · 73 complexity · 9cdef11d4212a34245da79f95959979b MD5 · raw file

  1. #if !ONLY_MISC_BUILD
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using System.Reflection.Emit;
  6. using System.Threading;
  7. namespace Demo.Mmose.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. }
  214. else generator.Emit( OpCodes.Ldind_Ref );
  215. }
  216. else
  217. {
  218. if ( paramTypes[iArgs].IsValueType )
  219. generator.Emit( OpCodes.Box, paramTypes[iArgs] );
  220. }
  221. generator.Emit( OpCodes.Stelem_Ref );
  222. if ( paramTypes[iArgs].IsByRef )
  223. {
  224. generator.Emit( OpCodes.Ldloc_2 );
  225. generator.Emit( OpCodes.Ldc_I4, iOutArgs );
  226. generator.Emit( OpCodes.Ldc_I4, iArgs );
  227. generator.Emit( OpCodes.Stelem_I4 );
  228. refArgs[iOutArgs] = iArgs;
  229. iOutArgs++;
  230. }
  231. if ( paramInfo[iArgs].IsIn || ( !paramInfo[iArgs].IsOut ) )
  232. {
  233. generator.Emit( OpCodes.Ldloc_1 );
  234. generator.Emit( OpCodes.Ldc_I4, iInArgs );
  235. generator.Emit( OpCodes.Ldarg, iArgs + 1 );
  236. if ( paramTypes[iArgs].IsByRef )
  237. {
  238. if ( paramTypes[iArgs].GetElementType().IsValueType )
  239. {
  240. generator.Emit( OpCodes.Ldobj, paramTypes[iArgs].GetElementType() );
  241. generator.Emit( OpCodes.Box, paramTypes[iArgs].GetElementType() );
  242. }
  243. else generator.Emit( OpCodes.Ldind_Ref );
  244. }
  245. else
  246. {
  247. if ( paramTypes[iArgs].IsValueType )
  248. generator.Emit( OpCodes.Box, paramTypes[iArgs] );
  249. }
  250. generator.Emit( OpCodes.Stelem_Ref );
  251. iInArgs++;
  252. }
  253. }
  254. // Calls the callFunction method of the base class
  255. generator.Emit( OpCodes.Ldarg_0 );
  256. generator.Emit( OpCodes.Ldloc_0 );
  257. generator.Emit( OpCodes.Ldloc_1 );
  258. generator.Emit( OpCodes.Ldloc_2 );
  259. MethodInfo miGenericEventHandler;
  260. miGenericEventHandler = delegateParent.GetMethod( "callFunction" );
  261. generator.Emit( OpCodes.Call, miGenericEventHandler );
  262. // Stores return value
  263. if ( returnType == typeof( void ) )
  264. {
  265. generator.Emit( OpCodes.Pop );
  266. generator.Emit( OpCodes.Ldnull );
  267. }
  268. else if ( returnType.IsValueType )
  269. {
  270. generator.Emit( OpCodes.Unbox, returnType );
  271. generator.Emit( OpCodes.Ldobj, returnType );
  272. }
  273. else generator.Emit( OpCodes.Castclass, returnType );
  274. generator.Emit( OpCodes.Stloc_3 );
  275. // Stores new value of out and ref params
  276. for ( int i = 0; i < refArgs.Length; i++ )
  277. {
  278. generator.Emit( OpCodes.Ldarg, refArgs[i] + 1 );
  279. generator.Emit( OpCodes.Ldloc_0 );
  280. generator.Emit( OpCodes.Ldc_I4, refArgs[i] );
  281. generator.Emit( OpCodes.Ldelem_Ref );
  282. if ( paramTypes[refArgs[i]].GetElementType().IsValueType )
  283. {
  284. generator.Emit( OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType() );
  285. generator.Emit( OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType() );
  286. generator.Emit( OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType() );
  287. }
  288. else
  289. {
  290. generator.Emit( OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType() );
  291. generator.Emit( OpCodes.Stind_Ref );
  292. }
  293. }
  294. // Returns
  295. if ( !( returnType == typeof( void ) ) )
  296. generator.Emit( OpCodes.Ldloc_3 );
  297. generator.Emit( OpCodes.Ret );
  298. // creates the new type
  299. return myType.CreateType();
  300. }
  301. /*
  302. * Generates an implementation of klass, if it is an interface, or
  303. * a subclass of klass that delegates its virtual methods to a Lua table.
  304. */
  305. public void GenerateClass( Type klass, out Type newType, out Type[][] returnTypes )
  306. {
  307. string typeName;
  308. lock ( this )
  309. {
  310. typeName = "LuaGeneratedClass" + luaClassNumber;
  311. luaClassNumber++;
  312. }
  313. TypeBuilder myType;
  314. // Define a public class in the assembly, called typeName
  315. if ( klass.IsInterface )
  316. myType = newModule.DefineType( typeName, TypeAttributes.Public, typeof( object ), new Type[] { klass, typeof( ILuaGeneratedType ) } );
  317. else
  318. myType = newModule.DefineType( typeName, TypeAttributes.Public, klass, new Type[] { typeof( ILuaGeneratedType ) } );
  319. // Field that stores the Lua table
  320. FieldBuilder luaTableField = myType.DefineField( "__luaInterface_luaTable", typeof( LuaTable ), FieldAttributes.Public );
  321. // Field that stores the return types array
  322. FieldBuilder returnTypesField = myType.DefineField( "__luaInterface_returnTypes", typeof( Type[][] ), FieldAttributes.Public );
  323. // Generates the constructor for the new type, it takes a Lua table and an array
  324. // of return types and stores them in the respective fields
  325. ConstructorBuilder constructor =
  326. myType.DefineConstructor( MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof( LuaTable ), typeof( Type[][] ) } );
  327. ILGenerator generator = constructor.GetILGenerator();
  328. generator.Emit( OpCodes.Ldarg_0 );
  329. if ( klass.IsInterface )
  330. generator.Emit( OpCodes.Call, typeof( object ).GetConstructor( Type.EmptyTypes ) );
  331. else
  332. generator.Emit( OpCodes.Call, klass.GetConstructor( Type.EmptyTypes ) );
  333. generator.Emit( OpCodes.Ldarg_0 );
  334. generator.Emit( OpCodes.Ldarg_1 );
  335. generator.Emit( OpCodes.Stfld, luaTableField );
  336. generator.Emit( OpCodes.Ldarg_0 );
  337. generator.Emit( OpCodes.Ldarg_2 );
  338. generator.Emit( OpCodes.Stfld, returnTypesField );
  339. generator.Emit( OpCodes.Ret );
  340. // Generates overriden versions of the klass' public virtual methods
  341. MethodInfo[] classMethods = klass.GetMethods();
  342. returnTypes = new Type[classMethods.Length][];
  343. int i = 0;
  344. foreach ( MethodInfo method in classMethods )
  345. {
  346. if ( klass.IsInterface )
  347. {
  348. GenerateMethod( myType, method,
  349. MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot,
  350. i, luaTableField, returnTypesField, false, out returnTypes[i] );
  351. i++;
  352. }
  353. else
  354. {
  355. if ( !method.IsPrivate && !method.IsFinal && method.IsVirtual )
  356. {
  357. GenerateMethod( myType, method, ( method.Attributes | MethodAttributes.NewSlot ) ^ MethodAttributes.NewSlot, i,
  358. luaTableField, returnTypesField, true, out returnTypes[i] );
  359. i++;
  360. }
  361. }
  362. }
  363. // Generates an implementation of the __luaInterface_getLuaTable method
  364. MethodBuilder returnTableMethod = myType.DefineMethod( "__luaInterface_getLuaTable",
  365. MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual,
  366. typeof( LuaTable ), new Type[0] );
  367. myType.DefineMethodOverride( returnTableMethod, typeof( ILuaGeneratedType ).GetMethod( "__luaInterface_getLuaTable" ) );
  368. generator = returnTableMethod.GetILGenerator();
  369. generator.Emit( OpCodes.Ldfld, luaTableField );
  370. generator.Emit( OpCodes.Ret );
  371. // Creates the type
  372. newType = myType.CreateType();
  373. }
  374. /*
  375. * Generates an overriden implementation of method inside myType that delegates
  376. * to a function in a Lua table with the same name, if the function exists. If it
  377. * doesn't the method calls the base method (or does nothing, in case of interface
  378. * implementations).
  379. */
  380. private void GenerateMethod( TypeBuilder myType, MethodInfo method, MethodAttributes attributes,
  381. int methodIndex, FieldInfo luaTableField, FieldInfo returnTypesField, bool generateBase, out Type[] returnTypes )
  382. {
  383. ParameterInfo[] paramInfo = method.GetParameters();
  384. Type[] paramTypes = new Type[paramInfo.Length];
  385. List<Type> returnTypesList = new List<Type>();
  386. // Counts out and ref parameters, for later use,
  387. // and creates the list of return types
  388. int nOutParams = 0; int nOutAndRefParams = 0;
  389. Type returnType = method.ReturnType;
  390. returnTypesList.Add( returnType );
  391. for ( int i = 0; i < paramTypes.Length; i++ )
  392. {
  393. paramTypes[i] = paramInfo[i].ParameterType;
  394. if ( ( !paramInfo[i].IsIn ) && paramInfo[i].IsOut )
  395. nOutParams++;
  396. if ( paramTypes[i].IsByRef )
  397. {
  398. returnTypesList.Add( paramTypes[i].GetElementType() );
  399. nOutAndRefParams++;
  400. }
  401. }
  402. int[] refArgs = new int[nOutAndRefParams];
  403. returnTypes = returnTypesList.ToArray();
  404. // Generates a version of the method that calls the base implementation
  405. // directly, for use by the base field of the table
  406. if ( generateBase )
  407. {
  408. MethodBuilder baseMethod = myType.DefineMethod( "__luaInterface_base_" + method.Name,
  409. MethodAttributes.Private | MethodAttributes.NewSlot | MethodAttributes.HideBySig,
  410. returnType, paramTypes );
  411. ILGenerator generatorBase = baseMethod.GetILGenerator();
  412. generatorBase.Emit( OpCodes.Ldarg_0 );
  413. for ( int i = 0; i < paramTypes.Length; i++ )
  414. generatorBase.Emit( OpCodes.Ldarg, i + 1 );
  415. generatorBase.Emit( OpCodes.Call, method );
  416. if ( returnType == typeof( void ) )
  417. generatorBase.Emit( OpCodes.Pop );
  418. generatorBase.Emit( OpCodes.Ret );
  419. }
  420. // Defines the method
  421. MethodBuilder methodImpl = myType.DefineMethod( method.Name, attributes,
  422. returnType, paramTypes );
  423. // If it's an implementation of an interface tells what method it
  424. // is overriding
  425. if ( myType.BaseType.Equals( typeof( object ) ) )
  426. myType.DefineMethodOverride( methodImpl, method );
  427. ILGenerator generator = methodImpl.GetILGenerator();
  428. generator.DeclareLocal( typeof( object[] ) ); // original arguments
  429. generator.DeclareLocal( typeof( object[] ) ); // with out-only arguments removed
  430. generator.DeclareLocal( typeof( int[] ) ); // indexes of out and ref arguments
  431. if ( !( returnType == typeof( void ) ) ) // return value
  432. generator.DeclareLocal( returnType );
  433. else
  434. generator.DeclareLocal( typeof( object ) );
  435. // Initializes local variables
  436. generator.Emit( OpCodes.Ldc_I4, paramTypes.Length );
  437. generator.Emit( OpCodes.Newarr, typeof( object ) );
  438. generator.Emit( OpCodes.Stloc_0 );
  439. generator.Emit( OpCodes.Ldc_I4, paramTypes.Length - nOutParams + 1 );
  440. generator.Emit( OpCodes.Newarr, typeof( object ) );
  441. generator.Emit( OpCodes.Stloc_1 );
  442. generator.Emit( OpCodes.Ldc_I4, nOutAndRefParams );
  443. generator.Emit( OpCodes.Newarr, typeof( int ) );
  444. generator.Emit( OpCodes.Stloc_2 );
  445. generator.Emit( OpCodes.Ldloc_1 );
  446. generator.Emit( OpCodes.Ldc_I4_0 );
  447. generator.Emit( OpCodes.Ldarg_0 );
  448. generator.Emit( OpCodes.Ldfld, luaTableField );
  449. generator.Emit( OpCodes.Stelem_Ref );
  450. // Stores the arguments into the local variables, as needed
  451. for ( int iArgs = 0, iInArgs = 1, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++ )
  452. {
  453. generator.Emit( OpCodes.Ldloc_0 );
  454. generator.Emit( OpCodes.Ldc_I4, iArgs );
  455. generator.Emit( OpCodes.Ldarg, iArgs + 1 );
  456. if ( paramTypes[iArgs].IsByRef )
  457. {
  458. if ( paramTypes[iArgs].GetElementType().IsValueType )
  459. {
  460. generator.Emit( OpCodes.Ldobj, paramTypes[iArgs].GetElementType() );
  461. generator.Emit( OpCodes.Box, paramTypes[iArgs].GetElementType() );
  462. }
  463. else generator.Emit( OpCodes.Ldind_Ref );
  464. }
  465. else
  466. {
  467. if ( paramTypes[iArgs].IsValueType )
  468. generator.Emit( OpCodes.Box, paramTypes[iArgs] );
  469. }
  470. generator.Emit( OpCodes.Stelem_Ref );
  471. if ( paramTypes[iArgs].IsByRef )
  472. {
  473. generator.Emit( OpCodes.Ldloc_2 );
  474. generator.Emit( OpCodes.Ldc_I4, iOutArgs );
  475. generator.Emit( OpCodes.Ldc_I4, iArgs );
  476. generator.Emit( OpCodes.Stelem_I4 );
  477. refArgs[iOutArgs] = iArgs;
  478. iOutArgs++;
  479. }
  480. if ( paramInfo[iArgs].IsIn || ( !paramInfo[iArgs].IsOut ) )
  481. {
  482. generator.Emit( OpCodes.Ldloc_1 );
  483. generator.Emit( OpCodes.Ldc_I4, iInArgs );
  484. generator.Emit( OpCodes.Ldarg, iArgs + 1 );
  485. if ( paramTypes[iArgs].IsByRef )
  486. {
  487. if ( paramTypes[iArgs].GetElementType().IsValueType )
  488. {
  489. generator.Emit( OpCodes.Ldobj, paramTypes[iArgs].GetElementType() );
  490. generator.Emit( OpCodes.Box, paramTypes[iArgs].GetElementType() );
  491. }
  492. else generator.Emit( OpCodes.Ldind_Ref );
  493. }
  494. else
  495. {
  496. if ( paramTypes[iArgs].IsValueType )
  497. generator.Emit( OpCodes.Box, paramTypes[iArgs] );
  498. }
  499. generator.Emit( OpCodes.Stelem_Ref );
  500. iInArgs++;
  501. }
  502. }
  503. // Gets the function the method will delegate to by calling
  504. // the getTableFunction method of class LuaClassHelper
  505. generator.Emit( OpCodes.Ldarg_0 );
  506. generator.Emit( OpCodes.Ldfld, luaTableField );
  507. generator.Emit( OpCodes.Ldstr, method.Name );
  508. generator.Emit( OpCodes.Call, classHelper.GetMethod( "getTableFunction" ) );
  509. Label lab1 = generator.DefineLabel();
  510. generator.Emit( OpCodes.Dup );
  511. generator.Emit( OpCodes.Brtrue_S, lab1 );
  512. // Function does not exist, call base method
  513. generator.Emit( OpCodes.Pop );
  514. if ( !method.IsAbstract )
  515. {
  516. generator.Emit( OpCodes.Ldarg_0 );
  517. for ( int i = 0; i < paramTypes.Length; i++ )
  518. generator.Emit( OpCodes.Ldarg, i + 1 );
  519. generator.Emit( OpCodes.Call, method );
  520. if ( returnType == typeof( void ) )
  521. generator.Emit( OpCodes.Pop );
  522. generator.Emit( OpCodes.Ret );
  523. generator.Emit( OpCodes.Ldnull );
  524. }
  525. else
  526. generator.Emit( OpCodes.Ldnull );
  527. Label lab2 = generator.DefineLabel();
  528. generator.Emit( OpCodes.Br_S, lab2 );
  529. generator.MarkLabel( lab1 );
  530. // Function exists, call using method callFunction of LuaClassHelper
  531. generator.Emit( OpCodes.Ldloc_0 );
  532. generator.Emit( OpCodes.Ldarg_0 );
  533. generator.Emit( OpCodes.Ldfld, returnTypesField );
  534. generator.Emit( OpCodes.Ldc_I4, methodIndex );
  535. generator.Emit( OpCodes.Ldelem_Ref );
  536. generator.Emit( OpCodes.Ldloc_1 );
  537. generator.Emit( OpCodes.Ldloc_2 );
  538. generator.Emit( OpCodes.Call, classHelper.GetMethod( "callFunction" ) );
  539. generator.MarkLabel( lab2 );
  540. // Stores the function return value
  541. if ( returnType == typeof( void ) )
  542. {
  543. generator.Emit( OpCodes.Pop );
  544. generator.Emit( OpCodes.Ldnull );
  545. }
  546. else if ( returnType.IsValueType )
  547. {
  548. generator.Emit( OpCodes.Unbox, returnType );
  549. generator.Emit( OpCodes.Ldobj, returnType );
  550. }
  551. else generator.Emit( OpCodes.Castclass, returnType );
  552. generator.Emit( OpCodes.Stloc_3 );
  553. // Sets return values of out and ref parameters
  554. for ( int i = 0; i < refArgs.Length; i++ )
  555. {
  556. generator.Emit( OpCodes.Ldarg, refArgs[i] + 1 );
  557. generator.Emit( OpCodes.Ldloc_0 );
  558. generator.Emit( OpCodes.Ldc_I4, refArgs[i] );
  559. generator.Emit( OpCodes.Ldelem_Ref );
  560. if ( paramTypes[refArgs[i]].GetElementType().IsValueType )
  561. {
  562. generator.Emit( OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType() );
  563. generator.Emit( OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType() );
  564. generator.Emit( OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType() );
  565. }
  566. else
  567. {
  568. generator.Emit( OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType() );
  569. generator.Emit( OpCodes.Stind_Ref );
  570. }
  571. }
  572. // Returns
  573. if ( !( returnType == typeof( void ) ) )
  574. generator.Emit( OpCodes.Ldloc_3 );
  575. generator.Emit( OpCodes.Ret );
  576. }
  577. /*
  578. * Gets an event handler for the event type that delegates to the eventHandler Lua function.
  579. * Caches the generated type.
  580. */
  581. public LuaEventHandler GetEvent( Type eventHandlerType, LuaFunction eventHandler )
  582. {
  583. Type eventConsumerType;
  584. if ( eventHandlerCollection.ContainsKey( eventHandlerType ) )
  585. {
  586. eventConsumerType = eventHandlerCollection[eventHandlerType];
  587. }
  588. else
  589. {
  590. eventConsumerType = GenerateEvent( eventHandlerType );
  591. eventHandlerCollection[eventHandlerType] = eventConsumerType;
  592. }
  593. LuaEventHandler luaEventHandler = (LuaEventHandler)Activator.CreateInstance( eventConsumerType );
  594. luaEventHandler.handler = eventHandler;
  595. return luaEventHandler;
  596. }
  597. /*
  598. * Gets a delegate with delegateType that calls the luaFunc Lua function
  599. * Caches the generated type.
  600. */
  601. public Delegate GetDelegate( Type delegateType, LuaFunction luaFunc )
  602. {
  603. List<Type> returnTypes = new List<Type>();
  604. Type luaDelegateType;
  605. if ( delegateCollection.ContainsKey( delegateType ) )
  606. {
  607. luaDelegateType = delegateCollection[delegateType];
  608. }
  609. else
  610. {
  611. luaDelegateType = GenerateDelegate( delegateType );
  612. delegateCollection[delegateType] = luaDelegateType;
  613. }
  614. MethodInfo methodInfo = delegateType.GetMethod( "Invoke" );
  615. returnTypes.Add( methodInfo.ReturnType );
  616. foreach ( ParameterInfo paramInfo in methodInfo.GetParameters() )
  617. if ( paramInfo.ParameterType.IsByRef )
  618. returnTypes.Add( paramInfo.ParameterType );
  619. LuaDelegate luaDelegate = (LuaDelegate)Activator.CreateInstance( luaDelegateType );
  620. luaDelegate.function = luaFunc;
  621. luaDelegate.returnTypes = returnTypes.ToArray();
  622. return Delegate.CreateDelegate( delegateType, luaDelegate, "CallFunction" );
  623. }
  624. /*
  625. * Gets an instance of an implementation of the klass interface or
  626. * subclass of klass that delegates public virtual methods to the
  627. * luaTable table.
  628. * Caches the generated type.
  629. */
  630. public object GetClassInstance( Type klass, LuaTable luaTable )
  631. {
  632. LuaClassType luaClassType;
  633. if ( classCollection.ContainsKey( klass ) )
  634. {
  635. luaClassType = classCollection[klass];
  636. }
  637. else
  638. {
  639. luaClassType = new LuaClassType();
  640. GenerateClass( klass, out luaClassType.klass, out luaClassType.returnTypes );
  641. classCollection[klass] = luaClassType;
  642. }
  643. return Activator.CreateInstance( luaClassType.klass, new object[] { luaTable, luaClassType.returnTypes } );
  644. }
  645. }
  646. }
  647. #endif