EmitContext.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. //
  2. // EmitContext.cs
  3. //
  4. // Author:
  5. // Miguel de Icaza ([email protected])
  6. // Jb Evain ([email protected])
  7. //
  8. // (C) 2008 Novell, Inc. (http://www.novell.com)
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Collections.ObjectModel;
  31. using System.Collections.Generic;
  32. using System.IO;
  33. using System.Linq;
  34. using System.Reflection;
  35. using System.Reflection.Emit;
  36. using System.Runtime.CompilerServices;
  37. namespace System.Linq.Expressions {
  38. class CompilationContext {
  39. List<object> globals = new List<object> ();
  40. List<EmitContext> units = new List<EmitContext> ();
  41. public int AddGlobal (object global)
  42. {
  43. return AddItemToList (global, globals);
  44. }
  45. public object [] GetGlobals ()
  46. {
  47. return globals.ToArray ();
  48. }
  49. static int AddItemToList<T> (T item, IList<T> list)
  50. {
  51. list.Add (item);
  52. return list.Count - 1;
  53. }
  54. public int AddCompilationUnit (LambdaExpression lambda)
  55. {
  56. var context = new EmitContext (this, lambda);
  57. var unit = AddItemToList (context, units);
  58. context.Emit ();
  59. return unit;
  60. }
  61. public Delegate CreateDelegate ()
  62. {
  63. return CreateDelegate (0, new ExecutionScope (this));
  64. }
  65. public Delegate CreateDelegate (int unit, ExecutionScope scope)
  66. {
  67. return units [unit].CreateDelegate (scope);
  68. }
  69. }
  70. class EmitContext {
  71. LambdaExpression owner;
  72. CompilationContext context;
  73. DynamicMethod method;
  74. public ILGenerator ig;
  75. public EmitContext (CompilationContext context, LambdaExpression lambda)
  76. {
  77. this.context = context;
  78. this.owner = lambda;
  79. method = new DynamicMethod ("lambda_method", owner.GetReturnType (),
  80. CreateParameterTypes (owner.Parameters), typeof (ExecutionScope), true);
  81. ig = method.GetILGenerator ();
  82. }
  83. public void Emit ()
  84. {
  85. owner.EmitBody (this);
  86. }
  87. static Type [] CreateParameterTypes (ReadOnlyCollection<ParameterExpression> parameters)
  88. {
  89. var types = new Type [parameters.Count + 1];
  90. types [0] = typeof (ExecutionScope);
  91. for (int i = 0; i < parameters.Count; i++)
  92. types [i + 1] = parameters [i].Type;
  93. return types;
  94. }
  95. public int GetParameterPosition (ParameterExpression p)
  96. {
  97. int position = owner.Parameters.IndexOf (p);
  98. if (position == -1)
  99. throw new InvalidOperationException ("Parameter not in scope");
  100. return position + 1; // + 1 because 0 is the ExecutionScope
  101. }
  102. public Delegate CreateDelegate (ExecutionScope scope)
  103. {
  104. return method.CreateDelegate (owner.Type, scope);
  105. }
  106. public void Emit (Expression expression)
  107. {
  108. expression.Emit (this);
  109. }
  110. public LocalBuilder EmitStored (Expression expression)
  111. {
  112. var local = ig.DeclareLocal (expression.Type);
  113. expression.Emit (this);
  114. ig.Emit (OpCodes.Stloc, local);
  115. return local;
  116. }
  117. public void EmitLoadAddress (Expression expression)
  118. {
  119. ig.Emit (OpCodes.Ldloca, EmitStored (expression));
  120. }
  121. public void EmitLoadSubject (Expression expression)
  122. {
  123. if (expression.Type.IsValueType) {
  124. EmitLoadAddress (expression);
  125. return;
  126. }
  127. Emit (expression);
  128. }
  129. public void EmitLoadSubject (LocalBuilder local)
  130. {
  131. if (local.LocalType.IsValueType) {
  132. EmitLoadAddress (local);
  133. return;
  134. }
  135. EmitLoad (local);
  136. }
  137. public void EmitLoadAddress (LocalBuilder local)
  138. {
  139. ig.Emit (OpCodes.Ldloca, local);
  140. }
  141. public void EmitLoad (LocalBuilder local)
  142. {
  143. ig.Emit (OpCodes.Ldloc, local);
  144. }
  145. public void EmitCall (LocalBuilder local, ReadOnlyCollection<Expression> arguments, MethodInfo method)
  146. {
  147. EmitLoadSubject (local);
  148. EmitArguments (method, arguments);
  149. EmitCall (method);
  150. }
  151. public void EmitCall (LocalBuilder local, MethodInfo method)
  152. {
  153. EmitLoadSubject (local);
  154. EmitCall (method);
  155. }
  156. public void EmitCall (Expression expression, MethodInfo method)
  157. {
  158. if (!method.IsStatic)
  159. EmitLoadSubject (expression);
  160. EmitCall (method);
  161. }
  162. public void EmitCall (Expression expression, ReadOnlyCollection<Expression> arguments, MethodInfo method)
  163. {
  164. if (!method.IsStatic)
  165. EmitLoadSubject (expression);
  166. EmitArguments (method, arguments);
  167. EmitCall (method);
  168. }
  169. void EmitArguments (MethodInfo method, ReadOnlyCollection<Expression> arguments)
  170. {
  171. var parameters = method.GetParameters ();
  172. for (int i = 0; i < parameters.Length; i++) {
  173. var parameter = parameters [i];
  174. var argument = arguments [i];
  175. if (parameter.ParameterType.IsByRef) {
  176. ig.Emit (OpCodes.Ldloca, EmitStored (argument));
  177. continue;
  178. }
  179. Emit (arguments [i]);
  180. }
  181. }
  182. public void EmitCall (MethodInfo method)
  183. {
  184. ig.Emit (
  185. method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call,
  186. method);
  187. }
  188. public void EmitNullableHasValue (LocalBuilder local)
  189. {
  190. EmitCall (local, "get_HasValue");
  191. }
  192. public void EmitNullableInitialize (LocalBuilder local)
  193. {
  194. ig.Emit (OpCodes.Ldloca, local);
  195. ig.Emit (OpCodes.Initobj, local.LocalType);
  196. ig.Emit (OpCodes.Ldloc, local);
  197. }
  198. public void EmitNullableGetValue (LocalBuilder local)
  199. {
  200. EmitCall (local, "get_Value");
  201. }
  202. public void EmitNullableGetValueOrDefault (LocalBuilder local)
  203. {
  204. EmitCall (local, "GetValueOrDefault");
  205. }
  206. void EmitCall (LocalBuilder local, string method_name)
  207. {
  208. EmitCall (local, local.LocalType.GetMethod (method_name, Type.EmptyTypes));
  209. }
  210. public void EmitNullableNew (Type of)
  211. {
  212. ig.Emit (OpCodes.Newobj, of.GetConstructor (new [] { of.GetFirstGenericArgument () }));
  213. }
  214. public void EmitCollection<T> (IEnumerable<T> collection) where T : Expression
  215. {
  216. foreach (var expression in collection)
  217. expression.Emit (this);
  218. }
  219. public void EmitCollection (IEnumerable<ElementInit> initializers, LocalBuilder local)
  220. {
  221. foreach (var initializer in initializers)
  222. initializer.Emit (this, local);
  223. }
  224. public void EmitCollection (IEnumerable<MemberBinding> bindings, LocalBuilder local)
  225. {
  226. foreach (var binding in bindings)
  227. binding.Emit (this, local);
  228. }
  229. public void EmitIsInst (Expression expression, Type candidate)
  230. {
  231. expression.Emit (this);
  232. var type = expression.Type;
  233. if (type.IsValueType)
  234. ig.Emit (OpCodes.Box, type);
  235. ig.Emit (OpCodes.Isinst, candidate);
  236. }
  237. public void EmitScope ()
  238. {
  239. ig.Emit (OpCodes.Ldarg_0);
  240. }
  241. public void EmitReadGlobal (object global)
  242. {
  243. EmitReadGlobal (global, global.GetType ());
  244. }
  245. public void EmitReadGlobal (object global, Type type)
  246. {
  247. EmitScope ();
  248. ig.Emit (OpCodes.Ldfld, typeof (ExecutionScope).GetField ("Globals"));
  249. ig.Emit (OpCodes.Ldc_I4, AddGlobal (global, type));
  250. ig.Emit (OpCodes.Ldelem, typeof (object));
  251. var strongbox = type.MakeStrongBoxType ();
  252. ig.Emit (OpCodes.Isinst, strongbox);
  253. ig.Emit (OpCodes.Ldfld, strongbox.GetField ("Value"));
  254. }
  255. int AddGlobal (object value, Type type)
  256. {
  257. return context.AddGlobal (CreateStrongBox (value, type));
  258. }
  259. public void EmitCreateDelegate (LambdaExpression lambda)
  260. {
  261. EmitScope ();
  262. ig.Emit (OpCodes.Ldc_I4, AddChildContext (lambda));
  263. ig.Emit (OpCodes.Ldnull);
  264. ig.Emit (OpCodes.Callvirt, typeof (ExecutionScope).GetMethod ("CreateDelegate"));
  265. ig.Emit (OpCodes.Castclass, lambda.Type);
  266. }
  267. int AddChildContext (LambdaExpression lambda)
  268. {
  269. return context.AddCompilationUnit (lambda);
  270. }
  271. static object CreateStrongBox (object value, Type type)
  272. {
  273. return Activator.CreateInstance (
  274. type.MakeStrongBoxType (), value);
  275. }
  276. }
  277. }