CodeGenerationHelper.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. //
  2. // Permission is hereby granted, free of charge, to any person obtaining
  3. // a copy of this software and associated documentation files (the
  4. // "Software"), to deal in the Software without restriction, including
  5. // without limitation the rights to use, copy, modify, merge, publish,
  6. // distribute, sublicense, and/or sell copies of the Software, and to
  7. // permit persons to whom the Software is furnished to do so, subject to
  8. // the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be
  11. // included in all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  14. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  15. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  16. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  17. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  18. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  19. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  20. //
  21. // Copyright (C) Lluis Sanchez Gual, 2004
  22. //
  23. using System;
  24. using System.Collections;
  25. using System.Reflection.Emit;
  26. using System.Reflection;
  27. namespace Mono.CodeGeneration
  28. {
  29. public class CodeGenerationHelper
  30. {
  31. public static void GenerateMethodCall (ILGenerator gen, CodeExpression target, MethodBase method, params CodeExpression[] parameters)
  32. {
  33. Type[] ptypes = Type.EmptyTypes;
  34. // It could raise an error since GetParameters() on MethodBuilder is not supported.
  35. if (parameters.Length > 0) {
  36. ParameterInfo[] pars = method.GetParameters ();
  37. ptypes = new Type[pars.Length];
  38. for (int n=0; n<ptypes.Length; n++) ptypes[n] = pars[n].ParameterType;
  39. }
  40. GenerateMethodCall (gen, target, method, ptypes, parameters);
  41. }
  42. public static void GenerateMethodCall (ILGenerator gen, CodeExpression target, CodeMethod method, params CodeExpression[] parameters)
  43. {
  44. GenerateMethodCall (gen, target, method.MethodBase, method.ParameterTypes, parameters);
  45. }
  46. static void GenerateMethodCall (ILGenerator gen, CodeExpression target, MethodBase method, Type[] parameterTypes, params CodeExpression[] parameters)
  47. {
  48. OpCode callOp;
  49. if (parameterTypes.Length != parameters.Length)
  50. throw GetMethodException (method, "Invalid number of parameters, expected " + parameterTypes.Length + ", found " + parameters.Length + ".");
  51. if (!object.ReferenceEquals (target, null))
  52. {
  53. target.Generate (gen);
  54. Type targetType = target.GetResultType();
  55. if (targetType.IsValueType) {
  56. LocalBuilder lb = gen.DeclareLocal (targetType);
  57. gen.Emit (OpCodes.Stloc, lb);
  58. gen.Emit (OpCodes.Ldloca, lb);
  59. callOp = OpCodes.Call;
  60. }
  61. else
  62. callOp = OpCodes.Callvirt;
  63. }
  64. else
  65. callOp = OpCodes.Call;
  66. for (int n=0; n<parameterTypes.Length; n++) {
  67. try {
  68. CodeExpression par = parameters[n];
  69. par.Generate (gen);
  70. GenerateSafeConversion (gen, parameterTypes[n], par.GetResultType());
  71. }
  72. catch (InvalidOperationException ex) {
  73. throw GetMethodException (method, "Parameter " + n + ". " + ex.Message);
  74. }
  75. }
  76. if (method is MethodInfo)
  77. gen.Emit (callOp, (MethodInfo)method);
  78. else if (method is ConstructorInfo)
  79. gen.Emit (callOp, (ConstructorInfo)method);
  80. }
  81. public static Exception GetMethodException (MethodBase method, string msg)
  82. {
  83. return new InvalidOperationException ("Call to method " + method.DeclaringType + "." + method.Name + ": " + msg);
  84. }
  85. public static void GenerateSafeConversion (ILGenerator gen, Type targetType, Type sourceType)
  86. {
  87. if (!targetType.IsAssignableFrom (sourceType)) {
  88. throw new InvalidOperationException ("Invalid type conversion. Found '" + sourceType + "', expected '" + targetType + "'.");
  89. }
  90. if (targetType == typeof(object) && sourceType.IsValueType) {
  91. gen.Emit (OpCodes.Box, sourceType);
  92. }
  93. }
  94. public static void LoadFromPtr (ILGenerator ig, Type t)
  95. {
  96. if (t == typeof(int))
  97. ig.Emit (OpCodes.Ldind_I4);
  98. else if (t == typeof(uint))
  99. ig.Emit (OpCodes.Ldind_U4);
  100. else if (t == typeof(short))
  101. ig.Emit (OpCodes.Ldind_I2);
  102. else if (t == typeof(ushort))
  103. ig.Emit (OpCodes.Ldind_U2);
  104. else if (t == typeof(char))
  105. ig.Emit (OpCodes.Ldind_U2);
  106. else if (t == typeof(byte))
  107. ig.Emit (OpCodes.Ldind_U1);
  108. else if (t == typeof(sbyte))
  109. ig.Emit (OpCodes.Ldind_I1);
  110. else if (t == typeof(ulong))
  111. ig.Emit (OpCodes.Ldind_I8);
  112. else if (t == typeof(long))
  113. ig.Emit (OpCodes.Ldind_I8);
  114. else if (t == typeof(float))
  115. ig.Emit (OpCodes.Ldind_R4);
  116. else if (t == typeof(double))
  117. ig.Emit (OpCodes.Ldind_R8);
  118. else if (t == typeof(bool))
  119. ig.Emit (OpCodes.Ldind_I1);
  120. else if (t == typeof(IntPtr))
  121. ig.Emit (OpCodes.Ldind_I);
  122. else if (t.IsEnum) {
  123. if (t == typeof(Enum))
  124. ig.Emit (OpCodes.Ldind_Ref);
  125. else
  126. LoadFromPtr (ig, System.Enum.GetUnderlyingType (t));
  127. } else if (t.IsValueType)
  128. ig.Emit (OpCodes.Ldobj, t);
  129. else
  130. ig.Emit (OpCodes.Ldind_Ref);
  131. }
  132. public static void SaveToPtr (ILGenerator ig, Type t)
  133. {
  134. if (t == typeof(int))
  135. ig.Emit (OpCodes.Stind_I4);
  136. else if (t == typeof(uint))
  137. ig.Emit (OpCodes.Stind_I4);
  138. else if (t == typeof(short))
  139. ig.Emit (OpCodes.Stind_I2);
  140. else if (t == typeof(ushort))
  141. ig.Emit (OpCodes.Stind_I2);
  142. else if (t == typeof(char))
  143. ig.Emit (OpCodes.Stind_I2);
  144. else if (t == typeof(byte))
  145. ig.Emit (OpCodes.Stind_I1);
  146. else if (t == typeof(sbyte))
  147. ig.Emit (OpCodes.Stind_I1);
  148. else if (t == typeof(ulong))
  149. ig.Emit (OpCodes.Stind_I8);
  150. else if (t == typeof(long))
  151. ig.Emit (OpCodes.Stind_I8);
  152. else if (t == typeof(float))
  153. ig.Emit (OpCodes.Stind_R4);
  154. else if (t == typeof(double))
  155. ig.Emit (OpCodes.Stind_R8);
  156. else if (t == typeof(bool))
  157. ig.Emit (OpCodes.Stind_I1);
  158. else if (t == typeof(IntPtr))
  159. ig.Emit (OpCodes.Stind_I);
  160. else if (t.IsEnum) {
  161. if (t == typeof(Enum))
  162. ig.Emit (OpCodes.Stind_Ref);
  163. else
  164. SaveToPtr (ig, System.Enum.GetUnderlyingType (t));
  165. } else if (t.IsValueType)
  166. ig.Emit (OpCodes.Stobj, t);
  167. else
  168. ig.Emit (OpCodes.Stind_Ref);
  169. }
  170. public static bool IsNumber (Type t)
  171. {
  172. switch (Type.GetTypeCode (t))
  173. {
  174. case TypeCode.Byte:
  175. case TypeCode.Double:
  176. case TypeCode.Int16:
  177. case TypeCode.Int32:
  178. case TypeCode.Int64:
  179. case TypeCode.SByte:
  180. case TypeCode.Single:
  181. case TypeCode.UInt16:
  182. case TypeCode.UInt32:
  183. case TypeCode.UInt64:
  184. return true;
  185. default:
  186. return false;
  187. }
  188. }
  189. public static void GeneratePrimitiveValue ()
  190. {
  191. }
  192. }
  193. }