PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/ClosersUnpacker/Lib/Linq4you/System.Linq.Expressions/EmitContext.cs

https://gitlab.com/gpo04174/ClosersCMFRepacker
C# | 608 lines | 459 code | 121 blank | 28 comment | 35 complexity | 9a4cbc9db9d7950fba0b7ce4ae0308c3 MD5 | raw file
  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 EmitLoadEnum (Expression expression)
  244. {
  245. expression.Emit (this);
  246. ig.Emit (OpCodes.Box, expression.Type);
  247. }
  248. public void EmitLoadEnum (LocalBuilder local)
  249. {
  250. ig.Emit (OpCodes.Ldloc, local);
  251. ig.Emit (OpCodes.Box, local.LocalType);
  252. }
  253. public void EmitLoadSubject (Expression expression)
  254. {
  255. if (expression.Type.IsEnum) {
  256. EmitLoadEnum (expression);
  257. return;
  258. }
  259. if (expression.Type.IsValueType) {
  260. EmitLoadAddress (expression);
  261. return;
  262. }
  263. Emit (expression);
  264. }
  265. public void EmitLoadSubject (LocalBuilder local)
  266. {
  267. if (local.LocalType.IsEnum) {
  268. EmitLoadEnum (local);
  269. return;
  270. }
  271. if (local.LocalType.IsValueType) {
  272. EmitLoadAddress (local);
  273. return;
  274. }
  275. EmitLoad (local);
  276. }
  277. public void EmitLoadAddress (LocalBuilder local)
  278. {
  279. ig.Emit (OpCodes.Ldloca, local);
  280. }
  281. public void EmitLoad (LocalBuilder local)
  282. {
  283. ig.Emit (OpCodes.Ldloc, local);
  284. }
  285. public void EmitCall (LocalBuilder local, IList<Expression> arguments, MethodInfo method)
  286. {
  287. EmitLoadSubject (local);
  288. EmitArguments (method, arguments);
  289. EmitCall (method);
  290. }
  291. public void EmitCall (LocalBuilder local, MethodInfo method)
  292. {
  293. EmitLoadSubject (local);
  294. EmitCall (method);
  295. }
  296. public void EmitCall (Expression expression, MethodInfo method)
  297. {
  298. if (!method.IsStatic)
  299. EmitLoadSubject (expression);
  300. EmitCall (method);
  301. }
  302. public void EmitCall (Expression expression, IList<Expression> arguments, MethodInfo method)
  303. {
  304. if (!method.IsStatic)
  305. EmitLoadSubject (expression);
  306. EmitArguments (method, arguments);
  307. EmitCall (method);
  308. }
  309. void EmitArguments (MethodInfo method, IList<Expression> arguments)
  310. {
  311. var parameters = method.GetParameters ();
  312. for (int i = 0; i < parameters.Length; i++) {
  313. var parameter = parameters [i];
  314. var argument = arguments [i];
  315. if (parameter.ParameterType.IsByRef) {
  316. ig.Emit (OpCodes.Ldloca, EmitStored (argument));
  317. continue;
  318. }
  319. Emit (arguments [i]);
  320. }
  321. }
  322. public void EmitCall (MethodInfo method)
  323. {
  324. ig.Emit (
  325. method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call,
  326. method);
  327. }
  328. public void EmitNullableHasValue (LocalBuilder local)
  329. {
  330. EmitCall (local, "get_HasValue");
  331. }
  332. public void EmitNullableInitialize (LocalBuilder local)
  333. {
  334. ig.Emit (OpCodes.Ldloca, local);
  335. ig.Emit (OpCodes.Initobj, local.LocalType);
  336. ig.Emit (OpCodes.Ldloc, local);
  337. }
  338. public void EmitNullableGetValue (LocalBuilder local)
  339. {
  340. EmitCall (local, "get_Value");
  341. }
  342. public void EmitNullableGetValueOrDefault (LocalBuilder local)
  343. {
  344. EmitCall (local, "GetValueOrDefault");
  345. }
  346. void EmitCall (LocalBuilder local, string method_name)
  347. {
  348. EmitCall (local, local.LocalType.GetMethod (method_name, Type.EmptyTypes));
  349. }
  350. public void EmitNullableNew (Type of)
  351. {
  352. ig.Emit (OpCodes.Newobj, of.GetConstructor (new [] { of.GetFirstGenericArgument () }));
  353. }
  354. public void EmitCollection<T> (IEnumerable<T> collection) where T : Expression
  355. {
  356. foreach (var expression in collection)
  357. expression.Emit (this);
  358. }
  359. public void EmitCollection (IEnumerable<ElementInit> initializers, LocalBuilder local)
  360. {
  361. foreach (var initializer in initializers)
  362. initializer.Emit (this, local);
  363. }
  364. public void EmitCollection (IEnumerable<MemberBinding> bindings, LocalBuilder local)
  365. {
  366. foreach (var binding in bindings)
  367. binding.Emit (this, local);
  368. }
  369. public void EmitIsInst (Expression expression, Type candidate)
  370. {
  371. expression.Emit (this);
  372. var type = expression.Type;
  373. if (type.IsValueType)
  374. ig.Emit (OpCodes.Box, type);
  375. ig.Emit (OpCodes.Isinst, candidate);
  376. }
  377. public void EmitScope ()
  378. {
  379. ig.Emit (OpCodes.Ldarg_0);
  380. }
  381. public void EmitReadGlobal (object global)
  382. {
  383. EmitReadGlobal (global, global.GetType ());
  384. }
  385. public void EmitLoadGlobals ()
  386. {
  387. EmitScope ();
  388. ig.Emit (OpCodes.Ldfld, typeof (ExecutionScope).GetField ("Globals"));
  389. }
  390. public void EmitReadGlobal (object global, Type type)
  391. {
  392. EmitLoadGlobals ();
  393. ig.Emit (OpCodes.Ldc_I4, AddGlobal (global, type));
  394. ig.Emit (OpCodes.Ldelem, typeof (object));
  395. EmitLoadStrongBoxValue (type);
  396. }
  397. public void EmitLoadStrongBoxValue (Type type)
  398. {
  399. var strongbox = type.MakeStrongBoxType ();
  400. ig.Emit (OpCodes.Isinst, strongbox);
  401. ig.Emit (OpCodes.Ldfld, strongbox.GetField ("Value"));
  402. }
  403. int AddGlobal (object value, Type type)
  404. {
  405. return context.AddGlobal (CreateStrongBox (value, type));
  406. }
  407. public void EmitCreateDelegate (LambdaExpression lambda)
  408. {
  409. EmitScope ();
  410. ig.Emit (OpCodes.Ldc_I4, AddChildContext (lambda));
  411. if (hoisted_store != null)
  412. ig.Emit (OpCodes.Ldloc, hoisted_store);
  413. else
  414. ig.Emit (OpCodes.Ldnull);
  415. ig.Emit (OpCodes.Callvirt, typeof (ExecutionScope).GetMethod ("CreateDelegate"));
  416. ig.Emit (OpCodes.Castclass, lambda.Type);
  417. }
  418. void EmitStoreHoistedLocals ()
  419. {
  420. EmitHoistedLocalsStore ();
  421. for (int i = 0; i < hoisted.Count; i++)
  422. EmitStoreHoistedLocal (i, hoisted [i]);
  423. }
  424. void EmitStoreHoistedLocal (int position, ParameterExpression parameter)
  425. {
  426. ig.Emit (OpCodes.Ldloc, hoisted_store);
  427. ig.Emit (OpCodes.Ldc_I4, position);
  428. parameter.Emit (this);
  429. EmitCreateStrongBox (parameter.Type);
  430. ig.Emit (OpCodes.Stelem, typeof (object));
  431. }
  432. public void EmitLoadHoistedLocalsStore ()
  433. {
  434. ig.Emit (OpCodes.Ldloc, hoisted_store);
  435. }
  436. void EmitCreateStrongBox (Type type)
  437. {
  438. ig.Emit (OpCodes.Newobj, type.MakeStrongBoxType ().GetConstructor (new [] { type }));
  439. }
  440. void EmitHoistedLocalsStore ()
  441. {
  442. EmitScope ();
  443. hoisted_store = ig.DeclareLocal (typeof (object []));
  444. ig.Emit (OpCodes.Callvirt, typeof (ExecutionScope).GetMethod ("CreateHoistedLocals"));
  445. ig.Emit (OpCodes.Stloc, hoisted_store);
  446. }
  447. public void EmitLoadLocals ()
  448. {
  449. ig.Emit (OpCodes.Ldfld, typeof (ExecutionScope).GetField ("Locals"));
  450. }
  451. public void EmitParentScope ()
  452. {
  453. ig.Emit (OpCodes.Ldfld, typeof (ExecutionScope).GetField ("Parent"));
  454. }
  455. public void EmitIsolateExpression ()
  456. {
  457. ig.Emit (OpCodes.Callvirt, typeof (ExecutionScope).GetMethod ("IsolateExpression"));
  458. }
  459. public int IndexOfHoistedLocal (ParameterExpression parameter)
  460. {
  461. if (!HasHoistedLocals)
  462. return -1;
  463. return hoisted.IndexOf (parameter);
  464. }
  465. public bool IsHoistedLocal (ParameterExpression parameter, ref int level, ref int position)
  466. {
  467. if (parent == null)
  468. return false;
  469. if (parent.hoisted != null) {
  470. position = parent.hoisted.IndexOf (parameter);
  471. if (position > -1)
  472. return true;
  473. }
  474. level++;
  475. return parent.IsHoistedLocal (parameter, ref level, ref position);
  476. }
  477. int AddChildContext (LambdaExpression lambda)
  478. {
  479. return context.AddCompilationUnit (this, lambda);
  480. }
  481. static object CreateStrongBox (object value, Type type)
  482. {
  483. return Activator.CreateInstance (
  484. type.MakeStrongBoxType (), value);
  485. }
  486. }
  487. }