CodeGenerationHelper.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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. #if !FULL_AOT_RUNTIME
  24. using System;
  25. using System.Collections;
  26. using System.Reflection.Emit;
  27. using System.Reflection;
  28. namespace Mono.CodeGeneration
  29. {
  30. public class CodeGenerationHelper
  31. {
  32. public static void GenerateMethodCall (ILGenerator gen, CodeExpression target, MethodBase method, params CodeExpression[] parameters)
  33. {
  34. Type[] ptypes = Type.EmptyTypes;
  35. // It could raise an error since GetParameters() on MethodBuilder is not supported.
  36. if (parameters.Length > 0) {
  37. ParameterInfo[] pars = method.GetParameters ();
  38. ptypes = new Type[pars.Length];
  39. for (int n=0; n<ptypes.Length; n++) ptypes[n] = pars[n].ParameterType;
  40. }
  41. GenerateMethodCall (gen, target, method, ptypes, parameters);
  42. }
  43. public static void GenerateMethodCall (ILGenerator gen, CodeExpression target, CodeMethod method, params CodeExpression[] parameters)
  44. {
  45. GenerateMethodCall (gen, target, method.MethodBase, method.ParameterTypes, parameters);
  46. }
  47. static void GenerateMethodCall (ILGenerator gen, CodeExpression target, MethodBase method, Type[] parameterTypes, params CodeExpression[] parameters)
  48. {
  49. OpCode callOp;
  50. if (parameterTypes.Length != parameters.Length)
  51. throw GetMethodException (method, "Invalid number of parameters, expected " + parameterTypes.Length + ", found " + parameters.Length + ".");
  52. if (!object.ReferenceEquals (target, null))
  53. {
  54. target.Generate (gen);
  55. Type targetType = target.GetResultType();
  56. if (targetType.IsValueType) {
  57. LocalBuilder lb = gen.DeclareLocal (targetType);
  58. gen.Emit (OpCodes.Stloc, lb);
  59. gen.Emit (OpCodes.Ldloca, lb);
  60. callOp = OpCodes.Call;
  61. }
  62. else
  63. callOp = OpCodes.Callvirt;
  64. }
  65. else
  66. callOp = OpCodes.Call;
  67. for (int n=0; n<parameterTypes.Length; n++) {
  68. try {
  69. CodeExpression par = parameters[n];
  70. par.Generate (gen);
  71. GenerateSafeConversion (gen, parameterTypes[n], par.GetResultType());
  72. }
  73. catch (InvalidOperationException ex) {
  74. throw GetMethodException (method, "Parameter " + n + ". " + ex.Message);
  75. }
  76. }
  77. if (method is MethodInfo)
  78. gen.Emit (callOp, (MethodInfo)method);
  79. else if (method is ConstructorInfo)
  80. gen.Emit (callOp, (ConstructorInfo)method);
  81. }
  82. public static Exception GetMethodException (MethodBase method, string msg)
  83. {
  84. return new InvalidOperationException ("Call to method " + method.DeclaringType + "." + method.Name + ": " + msg);
  85. }
  86. public static void GenerateSafeConversion (ILGenerator gen, Type targetType, Type sourceType)
  87. {
  88. if (!targetType.IsAssignableFrom (sourceType)) {
  89. throw new InvalidOperationException ("Invalid type conversion. Found '" + sourceType + "', expected '" + targetType + "'.");
  90. }
  91. if (targetType == typeof(object) && sourceType.IsValueType) {
  92. gen.Emit (OpCodes.Box, sourceType);
  93. }
  94. }
  95. public static void LoadFromPtr (ILGenerator ig, Type t)
  96. {
  97. if (t == typeof(int))
  98. ig.Emit (OpCodes.Ldind_I4);
  99. else if (t == typeof(uint))
  100. ig.Emit (OpCodes.Ldind_U4);
  101. else if (t == typeof(short))
  102. ig.Emit (OpCodes.Ldind_I2);
  103. else if (t == typeof(ushort))
  104. ig.Emit (OpCodes.Ldind_U2);
  105. else if (t == typeof(char))
  106. ig.Emit (OpCodes.Ldind_U2);
  107. else if (t == typeof(byte))
  108. ig.Emit (OpCodes.Ldind_U1);
  109. else if (t == typeof(sbyte))
  110. ig.Emit (OpCodes.Ldind_I1);
  111. else if (t == typeof(ulong))
  112. ig.Emit (OpCodes.Ldind_I8);
  113. else if (t == typeof(long))
  114. ig.Emit (OpCodes.Ldind_I8);
  115. else if (t == typeof(float))
  116. ig.Emit (OpCodes.Ldind_R4);
  117. else if (t == typeof(double))
  118. ig.Emit (OpCodes.Ldind_R8);
  119. else if (t == typeof(bool))
  120. ig.Emit (OpCodes.Ldind_I1);
  121. else if (t == typeof(IntPtr))
  122. ig.Emit (OpCodes.Ldind_I);
  123. else if (t.IsEnum) {
  124. if (t == typeof(Enum))
  125. ig.Emit (OpCodes.Ldind_Ref);
  126. else
  127. LoadFromPtr (ig, System.Enum.GetUnderlyingType (t));
  128. } else if (t.IsValueType)
  129. ig.Emit (OpCodes.Ldobj, t);
  130. else
  131. ig.Emit (OpCodes.Ldind_Ref);
  132. }
  133. public static void SaveToPtr (ILGenerator ig, Type t)
  134. {
  135. if (t == typeof(int))
  136. ig.Emit (OpCodes.Stind_I4);
  137. else if (t == typeof(uint))
  138. ig.Emit (OpCodes.Stind_I4);
  139. else if (t == typeof(short))
  140. ig.Emit (OpCodes.Stind_I2);
  141. else if (t == typeof(ushort))
  142. ig.Emit (OpCodes.Stind_I2);
  143. else if (t == typeof(char))
  144. ig.Emit (OpCodes.Stind_I2);
  145. else if (t == typeof(byte))
  146. ig.Emit (OpCodes.Stind_I1);
  147. else if (t == typeof(sbyte))
  148. ig.Emit (OpCodes.Stind_I1);
  149. else if (t == typeof(ulong))
  150. ig.Emit (OpCodes.Stind_I8);
  151. else if (t == typeof(long))
  152. ig.Emit (OpCodes.Stind_I8);
  153. else if (t == typeof(float))
  154. ig.Emit (OpCodes.Stind_R4);
  155. else if (t == typeof(double))
  156. ig.Emit (OpCodes.Stind_R8);
  157. else if (t == typeof(bool))
  158. ig.Emit (OpCodes.Stind_I1);
  159. else if (t == typeof(IntPtr))
  160. ig.Emit (OpCodes.Stind_I);
  161. else if (t.IsEnum) {
  162. if (t == typeof(Enum))
  163. ig.Emit (OpCodes.Stind_Ref);
  164. else
  165. SaveToPtr (ig, System.Enum.GetUnderlyingType (t));
  166. } else if (t.IsValueType)
  167. ig.Emit (OpCodes.Stobj, t);
  168. else
  169. ig.Emit (OpCodes.Stind_Ref);
  170. }
  171. public static bool IsNumber (Type t)
  172. {
  173. switch (Type.GetTypeCode (t))
  174. {
  175. case TypeCode.Byte:
  176. case TypeCode.Double:
  177. case TypeCode.Int16:
  178. case TypeCode.Int32:
  179. case TypeCode.Int64:
  180. case TypeCode.SByte:
  181. case TypeCode.Single:
  182. case TypeCode.UInt16:
  183. case TypeCode.UInt32:
  184. case TypeCode.UInt64:
  185. return true;
  186. default:
  187. return false;
  188. }
  189. }
  190. public static void GeneratePrimitiveValue ()
  191. {
  192. }
  193. }
  194. }
  195. #endif