PageRenderTime 60ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Core/System.Linq.Expressions/EmitContext.cs

https://bitbucket.org/steenlund/mono-2.6.7-for-amiga
C# | 586 lines | 441 code | 117 blank | 28 comment | 33 complexity | 77e4077bc4dae51f9c5b850d0de22871 MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0, LGPL-2.1
  1. //
  2. // EmitContext.cs
  3. //
  4. // Author:
  5. // Miguel de Icaza (miguel@novell.com)
  6. // Jb Evain (jbevain@novell.com)
  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. class ParameterReplacer : ExpressionTransformer {
  40. CompilationContext context;
  41. ExecutionScope scope;
  42. object [] locals;
  43. public ParameterReplacer (CompilationContext context, ExecutionScope scope, object [] locals)
  44. {
  45. this.context = context;
  46. this.scope = scope;
  47. this.locals = locals;
  48. }
  49. protected override Expression VisitParameter (ParameterExpression parameter)
  50. {
  51. var scope = this.scope;
  52. var locals = this.locals;
  53. while (scope != null) {
  54. int position = IndexOfHoistedLocal (scope, parameter);
  55. if (position != -1)
  56. return ReadHoistedLocalFromArray (locals, position);
  57. locals = scope.Locals;
  58. scope = scope.Parent;
  59. }
  60. return parameter;
  61. }
  62. Expression ReadHoistedLocalFromArray (object [] locals, int position)
  63. {
  64. return Expression.Field (
  65. Expression.Convert (
  66. Expression.ArrayIndex (
  67. Expression.Constant (locals),
  68. Expression.Constant (position)),
  69. locals [position].GetType ()),
  70. "Value");
  71. }
  72. int IndexOfHoistedLocal (ExecutionScope scope, ParameterExpression parameter)
  73. {
  74. return context.units [scope.compilation_unit].IndexOfHoistedLocal (parameter);
  75. }
  76. }
  77. class HoistedVariableDetector : ExpressionVisitor {
  78. Dictionary<ParameterExpression, LambdaExpression> parameter_to_lambda =
  79. new Dictionary<ParameterExpression, LambdaExpression> ();
  80. Dictionary<LambdaExpression, List<ParameterExpression>> hoisted_map;
  81. LambdaExpression lambda;
  82. public Dictionary<LambdaExpression, List<ParameterExpression>> Process (LambdaExpression lambda)
  83. {
  84. Visit (lambda);
  85. return hoisted_map;
  86. }
  87. protected override void VisitLambda (LambdaExpression lambda)
  88. {
  89. this.lambda = lambda;
  90. foreach (var parameter in lambda.Parameters)
  91. parameter_to_lambda [parameter] = lambda;
  92. base.VisitLambda (lambda);
  93. }
  94. protected override void VisitParameter (ParameterExpression parameter)
  95. {
  96. if (lambda.Parameters.Contains (parameter))
  97. return;
  98. Hoist (parameter);
  99. }
  100. void Hoist (ParameterExpression parameter)
  101. {
  102. LambdaExpression lambda;
  103. if (!parameter_to_lambda.TryGetValue (parameter, out lambda))
  104. return;
  105. if (hoisted_map == null)
  106. hoisted_map = new Dictionary<LambdaExpression, List<ParameterExpression>> ();
  107. List<ParameterExpression> hoisted;
  108. if (!hoisted_map.TryGetValue (lambda, out hoisted)) {
  109. hoisted = new List<ParameterExpression> ();
  110. hoisted_map [lambda] = hoisted;
  111. }
  112. hoisted.Add (parameter);
  113. }
  114. }
  115. List<object> globals = new List<object> ();
  116. List<EmitContext> units = new List<EmitContext> ();
  117. Dictionary<LambdaExpression, List<ParameterExpression>> hoisted_map;
  118. public int AddGlobal (object global)
  119. {
  120. return AddItemToList (global, globals);
  121. }
  122. public object [] GetGlobals ()
  123. {
  124. return globals.ToArray ();
  125. }
  126. static int AddItemToList<T> (T item, IList<T> list)
  127. {
  128. list.Add (item);
  129. return list.Count - 1;
  130. }
  131. public int AddCompilationUnit (LambdaExpression lambda)
  132. {
  133. DetectHoistedVariables (lambda);
  134. return AddCompilationUnit (null, lambda);
  135. }
  136. public int AddCompilationUnit (EmitContext parent, LambdaExpression lambda)
  137. {
  138. var context = new EmitContext (this, parent, lambda);
  139. var unit = AddItemToList (context, units);
  140. context.Emit ();
  141. return unit;
  142. }
  143. void DetectHoistedVariables (LambdaExpression lambda)
  144. {
  145. hoisted_map = new HoistedVariableDetector ().Process (lambda);
  146. }
  147. public List<ParameterExpression> GetHoistedLocals (LambdaExpression lambda)
  148. {
  149. if (hoisted_map == null)
  150. return null;
  151. List<ParameterExpression> hoisted;
  152. hoisted_map.TryGetValue (lambda, out hoisted);
  153. return hoisted;
  154. }
  155. public object [] CreateHoistedLocals (int unit)
  156. {
  157. var hoisted = GetHoistedLocals (units [unit].Lambda);
  158. return new object [hoisted == null ? 0 : hoisted.Count];
  159. }
  160. public Expression IsolateExpression (ExecutionScope scope, object [] locals, Expression expression)
  161. {
  162. return new ParameterReplacer (this, scope, locals).Transform (expression);
  163. }
  164. public Delegate CreateDelegate ()
  165. {
  166. return CreateDelegate (0, new ExecutionScope (this));
  167. }
  168. public Delegate CreateDelegate (int unit, ExecutionScope scope)
  169. {
  170. return units [unit].CreateDelegate (scope);
  171. }
  172. }
  173. class EmitContext {
  174. CompilationContext context;
  175. EmitContext parent;
  176. LambdaExpression lambda;
  177. DynamicMethod method;
  178. LocalBuilder hoisted_store;
  179. List<ParameterExpression> hoisted;
  180. public readonly ILGenerator ig;
  181. public bool HasHoistedLocals {
  182. get { return hoisted != null && hoisted.Count > 0; }
  183. }
  184. public LambdaExpression Lambda {
  185. get { return lambda; }
  186. }
  187. public EmitContext (CompilationContext context, EmitContext parent, LambdaExpression lambda)
  188. {
  189. this.context = context;
  190. this.parent = parent;
  191. this.lambda = lambda;
  192. this.hoisted = context.GetHoistedLocals (lambda);
  193. method = new DynamicMethod (
  194. "lambda_method",
  195. lambda.GetReturnType (),
  196. CreateParameterTypes (lambda.Parameters),
  197. typeof (ExecutionScope),
  198. true);
  199. ig = method.GetILGenerator ();
  200. }
  201. public void Emit ()
  202. {
  203. if (HasHoistedLocals)
  204. EmitStoreHoistedLocals ();
  205. lambda.EmitBody (this);
  206. }
  207. static Type [] CreateParameterTypes (IList<ParameterExpression> parameters)
  208. {
  209. var types = new Type [parameters.Count + 1];
  210. types [0] = typeof (ExecutionScope);
  211. for (int i = 0; i < parameters.Count; i++)
  212. types [i + 1] = parameters [i].Type;
  213. return types;
  214. }
  215. public bool IsLocalParameter (ParameterExpression parameter, ref int position)
  216. {
  217. position = lambda.Parameters.IndexOf (parameter);
  218. if (position > -1) {
  219. position++;
  220. return true;
  221. }
  222. return false;
  223. }
  224. public Delegate CreateDelegate (ExecutionScope scope)
  225. {
  226. return method.CreateDelegate (lambda.Type, scope);
  227. }
  228. public void Emit (Expression expression)
  229. {
  230. expression.Emit (this);
  231. }
  232. public LocalBuilder EmitStored (Expression expression)
  233. {
  234. var local = ig.DeclareLocal (expression.Type);
  235. expression.Emit (this);
  236. ig.Emit (OpCodes.Stloc, local);
  237. return local;
  238. }
  239. public void EmitLoadAddress (Expression expression)
  240. {
  241. ig.Emit (OpCodes.Ldloca, EmitStored (expression));
  242. }
  243. public void EmitLoadSubject (Expression expression)
  244. {
  245. if (expression.Type.IsValueType) {
  246. EmitLoadAddress (expression);
  247. return;
  248. }
  249. Emit (expression);
  250. }
  251. public void EmitLoadSubject (LocalBuilder local)
  252. {
  253. if (local.LocalType.IsValueType) {
  254. EmitLoadAddress (local);
  255. return;
  256. }
  257. EmitLoad (local);
  258. }
  259. public void EmitLoadAddress (LocalBuilder local)
  260. {
  261. ig.Emit (OpCodes.Ldloca, local);
  262. }
  263. public void EmitLoad (LocalBuilder local)
  264. {
  265. ig.Emit (OpCodes.Ldloc, local);
  266. }
  267. public void EmitCall (LocalBuilder local, IList<Expression> arguments, MethodInfo method)
  268. {
  269. EmitLoadSubject (local);
  270. EmitArguments (method, arguments);
  271. EmitCall (method);
  272. }
  273. public void EmitCall (LocalBuilder local, MethodInfo method)
  274. {
  275. EmitLoadSubject (local);
  276. EmitCall (method);
  277. }
  278. public void EmitCall (Expression expression, MethodInfo method)
  279. {
  280. if (!method.IsStatic)
  281. EmitLoadSubject (expression);
  282. EmitCall (method);
  283. }
  284. public void EmitCall (Expression expression, IList<Expression> arguments, MethodInfo method)
  285. {
  286. if (!method.IsStatic)
  287. EmitLoadSubject (expression);
  288. EmitArguments (method, arguments);
  289. EmitCall (method);
  290. }
  291. void EmitArguments (MethodInfo method, IList<Expression> arguments)
  292. {
  293. var parameters = method.GetParameters ();
  294. for (int i = 0; i < parameters.Length; i++) {
  295. var parameter = parameters [i];
  296. var argument = arguments [i];
  297. if (parameter.ParameterType.IsByRef) {
  298. ig.Emit (OpCodes.Ldloca, EmitStored (argument));
  299. continue;
  300. }
  301. Emit (arguments [i]);
  302. }
  303. }
  304. public void EmitCall (MethodInfo method)
  305. {
  306. ig.Emit (
  307. method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call,
  308. method);
  309. }
  310. public void EmitNullableHasValue (LocalBuilder local)
  311. {
  312. EmitCall (local, "get_HasValue");
  313. }
  314. public void EmitNullableInitialize (LocalBuilder local)
  315. {
  316. ig.Emit (OpCodes.Ldloca, local);
  317. ig.Emit (OpCodes.Initobj, local.LocalType);
  318. ig.Emit (OpCodes.Ldloc, local);
  319. }
  320. public void EmitNullableGetValue (LocalBuilder local)
  321. {
  322. EmitCall (local, "get_Value");
  323. }
  324. public void EmitNullableGetValueOrDefault (LocalBuilder local)
  325. {
  326. EmitCall (local, "GetValueOrDefault");
  327. }
  328. void EmitCall (LocalBuilder local, string method_name)
  329. {
  330. EmitCall (local, local.LocalType.GetMethod (method_name, Type.EmptyTypes));
  331. }
  332. public void EmitNullableNew (Type of)
  333. {
  334. ig.Emit (OpCodes.Newobj, of.GetConstructor (new [] { of.GetFirstGenericArgument () }));
  335. }
  336. public void EmitCollection<T> (IEnumerable<T> collection) where T : Expression
  337. {
  338. foreach (var expression in collection)
  339. expression.Emit (this);
  340. }
  341. public void EmitCollection (IEnumerable<ElementInit> initializers, LocalBuilder local)
  342. {
  343. foreach (var initializer in initializers)
  344. initializer.Emit (this, local);
  345. }
  346. public void EmitCollection (IEnumerable<MemberBinding> bindings, LocalBuilder local)
  347. {
  348. foreach (var binding in bindings)
  349. binding.Emit (this, local);
  350. }
  351. public void EmitIsInst (Expression expression, Type candidate)
  352. {
  353. expression.Emit (this);
  354. var type = expression.Type;
  355. if (type.IsValueType)
  356. ig.Emit (OpCodes.Box, type);
  357. ig.Emit (OpCodes.Isinst, candidate);
  358. }
  359. public void EmitScope ()
  360. {
  361. ig.Emit (OpCodes.Ldarg_0);
  362. }
  363. public void EmitReadGlobal (object global)
  364. {
  365. EmitReadGlobal (global, global.GetType ());
  366. }
  367. public void EmitLoadGlobals ()
  368. {
  369. EmitScope ();
  370. ig.Emit (OpCodes.Ldfld, typeof (ExecutionScope).GetField ("Globals"));
  371. }
  372. public void EmitReadGlobal (object global, Type type)
  373. {
  374. EmitLoadGlobals ();
  375. ig.Emit (OpCodes.Ldc_I4, AddGlobal (global, type));
  376. ig.Emit (OpCodes.Ldelem, typeof (object));
  377. EmitLoadStrongBoxValue (type);
  378. }
  379. public void EmitLoadStrongBoxValue (Type type)
  380. {
  381. var strongbox = type.MakeStrongBoxType ();
  382. ig.Emit (OpCodes.Isinst, strongbox);
  383. ig.Emit (OpCodes.Ldfld, strongbox.GetField ("Value"));
  384. }
  385. int AddGlobal (object value, Type type)
  386. {
  387. return context.AddGlobal (CreateStrongBox (value, type));
  388. }
  389. public void EmitCreateDelegate (LambdaExpression lambda)
  390. {
  391. EmitScope ();
  392. ig.Emit (OpCodes.Ldc_I4, AddChildContext (lambda));
  393. if (hoisted_store != null)
  394. ig.Emit (OpCodes.Ldloc, hoisted_store);
  395. else
  396. ig.Emit (OpCodes.Ldnull);
  397. ig.Emit (OpCodes.Callvirt, typeof (ExecutionScope).GetMethod ("CreateDelegate"));
  398. ig.Emit (OpCodes.Castclass, lambda.Type);
  399. }
  400. void EmitStoreHoistedLocals ()
  401. {
  402. EmitHoistedLocalsStore ();
  403. for (int i = 0; i < hoisted.Count; i++)
  404. EmitStoreHoistedLocal (i, hoisted [i]);
  405. }
  406. void EmitStoreHoistedLocal (int position, ParameterExpression parameter)
  407. {
  408. ig.Emit (OpCodes.Ldloc, hoisted_store);
  409. ig.Emit (OpCodes.Ldc_I4, position);
  410. parameter.Emit (this);
  411. EmitCreateStrongBox (parameter.Type);
  412. ig.Emit (OpCodes.Stelem, typeof (object));
  413. }
  414. public void EmitLoadHoistedLocalsStore ()
  415. {
  416. ig.Emit (OpCodes.Ldloc, hoisted_store);
  417. }
  418. void EmitCreateStrongBox (Type type)
  419. {
  420. ig.Emit (OpCodes.Newobj, type.MakeStrongBoxType ().GetConstructor (new [] { type }));
  421. }
  422. void EmitHoistedLocalsStore ()
  423. {
  424. EmitScope ();
  425. hoisted_store = ig.DeclareLocal (typeof (object []));
  426. ig.Emit (OpCodes.Callvirt, typeof (ExecutionScope).GetMethod ("CreateHoistedLocals"));
  427. ig.Emit (OpCodes.Stloc, hoisted_store);
  428. }
  429. public void EmitLoadLocals ()
  430. {
  431. ig.Emit (OpCodes.Ldfld, typeof (ExecutionScope).GetField ("Locals"));
  432. }
  433. public void EmitParentScope ()
  434. {
  435. ig.Emit (OpCodes.Ldfld, typeof (ExecutionScope).GetField ("Parent"));
  436. }
  437. public void EmitIsolateExpression ()
  438. {
  439. ig.Emit (OpCodes.Callvirt, typeof (ExecutionScope).GetMethod ("IsolateExpression"));
  440. }
  441. public int IndexOfHoistedLocal (ParameterExpression parameter)
  442. {
  443. if (!HasHoistedLocals)
  444. return -1;
  445. return hoisted.IndexOf (parameter);
  446. }
  447. public bool IsHoistedLocal (ParameterExpression parameter, ref int level, ref int position)
  448. {
  449. if (parent == null)
  450. return false;
  451. if (parent.hoisted != null) {
  452. position = parent.hoisted.IndexOf (parameter);
  453. if (position > -1)
  454. return true;
  455. }
  456. level++;
  457. return parent.IsHoistedLocal (parameter, ref level, ref position);
  458. }
  459. int AddChildContext (LambdaExpression lambda)
  460. {
  461. return context.AddCompilationUnit (this, lambda);
  462. }
  463. static object CreateStrongBox (object value, Type type)
  464. {
  465. return Activator.CreateInstance (
  466. type.MakeStrongBoxType (), value);
  467. }
  468. }
  469. }