PageRenderTime 63ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/LambdaCompiler.Expressions.cs

https://bitbucket.org/danipen/mono
C# | 1085 lines | 805 code | 143 blank | 137 comment | 195 complexity | 81cc89fbe6384e7192e174787f67e658 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Collections.ObjectModel;
  18. using System.Diagnostics;
  19. using System.Dynamic.Utils;
  20. using System.Reflection;
  21. using System.Reflection.Emit;
  22. using System.Runtime.CompilerServices;
  23. #if !FEATURE_CORE_DLR
  24. namespace Microsoft.Scripting.Ast.Compiler {
  25. #else
  26. namespace System.Linq.Expressions.Compiler {
  27. #endif
  28. partial class LambdaCompiler {
  29. [Flags]
  30. internal enum CompilationFlags {
  31. EmitExpressionStart = 0x0001,
  32. EmitNoExpressionStart = 0x0002,
  33. EmitAsDefaultType = 0x0010,
  34. EmitAsVoidType = 0x0020,
  35. EmitAsTail = 0x0100, // at the tail position of a lambda, tail call can be safely emitted
  36. EmitAsMiddle = 0x0200, // in the middle of a lambda, tail call can be emitted if it is in a return
  37. EmitAsNoTail = 0x0400, // neither at the tail or in a return, or tail call is not turned on, no tail call is emitted
  38. EmitExpressionStartMask = 0x000f,
  39. EmitAsTypeMask = 0x00f0,
  40. EmitAsTailCallMask = 0x0f00
  41. }
  42. /// <summary>
  43. /// Update the flag with a new EmitAsTailCall flag
  44. /// </summary>
  45. private static CompilationFlags UpdateEmitAsTailCallFlag(CompilationFlags flags, CompilationFlags newValue) {
  46. Debug.Assert(newValue == CompilationFlags.EmitAsTail || newValue == CompilationFlags.EmitAsMiddle || newValue == CompilationFlags.EmitAsNoTail);
  47. var oldValue = flags & CompilationFlags.EmitAsTailCallMask;
  48. return flags ^ oldValue | newValue;
  49. }
  50. /// <summary>
  51. /// Update the flag with a new EmitExpressionStart flag
  52. /// </summary>
  53. private static CompilationFlags UpdateEmitExpressionStartFlag(CompilationFlags flags, CompilationFlags newValue) {
  54. Debug.Assert(newValue == CompilationFlags.EmitExpressionStart || newValue == CompilationFlags.EmitNoExpressionStart);
  55. var oldValue = flags & CompilationFlags.EmitExpressionStartMask;
  56. return flags ^ oldValue | newValue;
  57. }
  58. /// <summary>
  59. /// Update the flag with a new EmitAsType flag
  60. /// </summary>
  61. private static CompilationFlags UpdateEmitAsTypeFlag(CompilationFlags flags, CompilationFlags newValue) {
  62. Debug.Assert(newValue == CompilationFlags.EmitAsDefaultType || newValue == CompilationFlags.EmitAsVoidType);
  63. var oldValue = flags & CompilationFlags.EmitAsTypeMask;
  64. return flags ^ oldValue | newValue;
  65. }
  66. /// <summary>
  67. /// Generates code for this expression in a value position.
  68. /// This method will leave the value of the expression
  69. /// on the top of the stack typed as Type.
  70. /// </summary>
  71. internal void EmitExpression(Expression node) {
  72. EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitExpressionStart);
  73. }
  74. /// <summary>
  75. /// Emits an expression and discards the result. For some nodes this emits
  76. /// more optimial code then EmitExpression/Pop
  77. /// </summary>
  78. private void EmitExpressionAsVoid(Expression node) {
  79. EmitExpressionAsVoid(node, CompilationFlags.EmitAsNoTail);
  80. }
  81. private void EmitExpressionAsVoid(Expression node, CompilationFlags flags) {
  82. Debug.Assert(node != null);
  83. CompilationFlags startEmitted = EmitExpressionStart(node);
  84. switch (node.NodeType) {
  85. case ExpressionType.Assign:
  86. EmitAssign((BinaryExpression)node, CompilationFlags.EmitAsVoidType);
  87. break;
  88. case ExpressionType.Block:
  89. Emit((BlockExpression)node, UpdateEmitAsTypeFlag(flags, CompilationFlags.EmitAsVoidType));
  90. break;
  91. case ExpressionType.Throw:
  92. EmitThrow((UnaryExpression)node, CompilationFlags.EmitAsVoidType);
  93. break;
  94. case ExpressionType.Goto:
  95. EmitGotoExpression(node, UpdateEmitAsTypeFlag(flags, CompilationFlags.EmitAsVoidType));
  96. break;
  97. case ExpressionType.Constant:
  98. case ExpressionType.Default:
  99. case ExpressionType.Parameter:
  100. // no-op
  101. break;
  102. default:
  103. if (node.Type == typeof(void)) {
  104. EmitExpression(node, UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitNoExpressionStart));
  105. } else {
  106. EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
  107. _ilg.Emit(OpCodes.Pop);
  108. }
  109. break;
  110. }
  111. EmitExpressionEnd(startEmitted);
  112. }
  113. private void EmitExpressionAsType(Expression node, Type type, CompilationFlags flags) {
  114. if (type == typeof(void)) {
  115. EmitExpressionAsVoid(node, flags);
  116. } else {
  117. // if the node is emitted as a different type, CastClass IL is emitted at the end,
  118. // should not emit with tail calls.
  119. if (!TypeUtils.AreEquivalent(node.Type, type)) {
  120. EmitExpression(node);
  121. Debug.Assert(TypeUtils.AreReferenceAssignable(type, node.Type));
  122. _ilg.Emit(OpCodes.Castclass, type);
  123. } else {
  124. // emit the with the flags and emit emit expression start
  125. EmitExpression(node, UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart));
  126. }
  127. }
  128. }
  129. #region label block tracking
  130. private CompilationFlags EmitExpressionStart(Expression node) {
  131. if (TryPushLabelBlock(node)) {
  132. return CompilationFlags.EmitExpressionStart;
  133. }
  134. return CompilationFlags.EmitNoExpressionStart;
  135. }
  136. private void EmitExpressionEnd(CompilationFlags flags) {
  137. if ((flags & CompilationFlags.EmitExpressionStartMask) == CompilationFlags.EmitExpressionStart) {
  138. PopLabelBlock(_labelBlock.Kind);
  139. }
  140. }
  141. #endregion
  142. #region InvocationExpression
  143. private void EmitInvocationExpression(Expression expr, CompilationFlags flags) {
  144. InvocationExpression node = (InvocationExpression)expr;
  145. // Optimization: inline code for literal lambda's directly
  146. //
  147. // This is worth it because otherwise we end up with a extra call
  148. // to DynamicMethod.CreateDelegate, which is expensive.
  149. //
  150. if (node.LambdaOperand != null) {
  151. EmitInlinedInvoke(node, flags);
  152. return;
  153. }
  154. expr = node.Expression;
  155. if (typeof(LambdaExpression).IsAssignableFrom(expr.Type)) {
  156. // if the invoke target is a lambda expression tree, first compile it into a delegate
  157. expr = Expression.Call(expr, expr.Type.GetMethod("Compile", new Type[0]));
  158. }
  159. expr = Expression.Call(expr, expr.Type.GetMethod("Invoke"), node.Arguments);
  160. EmitExpression(expr);
  161. }
  162. private void EmitInlinedInvoke(InvocationExpression invoke, CompilationFlags flags) {
  163. var lambda = invoke.LambdaOperand;
  164. // This is tricky: we need to emit the arguments outside of the
  165. // scope, but set them inside the scope. Fortunately, using the IL
  166. // stack it is entirely doable.
  167. // 1. Emit invoke arguments
  168. List<WriteBack> wb = EmitArguments(lambda.Type.GetMethod("Invoke"), invoke);
  169. // 2. Create the nested LambdaCompiler
  170. var inner = new LambdaCompiler(this, lambda);
  171. // 3. Emit the body
  172. // if the inlined lambda is the last expression of the whole lambda,
  173. // tail call can be applied.
  174. if (wb.Count != 0) {
  175. flags = UpdateEmitAsTailCallFlag(flags, CompilationFlags.EmitAsNoTail);
  176. }
  177. inner.EmitLambdaBody(_scope, true, flags);
  178. // 4. Emit writebacks if needed
  179. EmitWriteBack(wb);
  180. }
  181. #endregion
  182. #region IndexExpression
  183. private void EmitIndexExpression(Expression expr) {
  184. var node = (IndexExpression)expr;
  185. // Emit instance, if calling an instance method
  186. Type objectType = null;
  187. if (node.Object != null) {
  188. EmitInstance(node.Object, objectType = node.Object.Type);
  189. }
  190. // Emit indexes. We don't allow byref args, so no need to worry
  191. // about writebacks or EmitAddress
  192. foreach (var arg in node.Arguments) {
  193. EmitExpression(arg);
  194. }
  195. EmitGetIndexCall(node, objectType);
  196. }
  197. private void EmitIndexAssignment(BinaryExpression node, CompilationFlags flags) {
  198. var index = (IndexExpression)node.Left;
  199. var emitAs = flags & CompilationFlags.EmitAsTypeMask;
  200. // Emit instance, if calling an instance method
  201. Type objectType = null;
  202. if (index.Object != null) {
  203. EmitInstance(index.Object, objectType = index.Object.Type);
  204. }
  205. // Emit indexes. We don't allow byref args, so no need to worry
  206. // about writebacks or EmitAddress
  207. foreach (var arg in index.Arguments) {
  208. EmitExpression(arg);
  209. }
  210. // Emit value
  211. EmitExpression(node.Right);
  212. // Save the expression value, if needed
  213. LocalBuilder temp = null;
  214. if (emitAs != CompilationFlags.EmitAsVoidType) {
  215. _ilg.Emit(OpCodes.Dup);
  216. _ilg.Emit(OpCodes.Stloc, temp = GetLocal(node.Type));
  217. }
  218. EmitSetIndexCall(index, objectType);
  219. // Restore the value
  220. if (emitAs != CompilationFlags.EmitAsVoidType) {
  221. _ilg.Emit(OpCodes.Ldloc, temp);
  222. FreeLocal(temp);
  223. }
  224. }
  225. private void EmitGetIndexCall(IndexExpression node, Type objectType) {
  226. if (node.Indexer != null) {
  227. // For indexed properties, just call the getter
  228. var method = node.Indexer.GetGetMethod(true);
  229. EmitCall(objectType, method);
  230. } else if (node.Arguments.Count != 1) {
  231. // Multidimensional arrays, call get
  232. _ilg.Emit(OpCodes.Call, node.Object.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance));
  233. } else {
  234. // For one dimensional arrays, emit load
  235. _ilg.EmitLoadElement(node.Type);
  236. }
  237. }
  238. private void EmitSetIndexCall(IndexExpression node, Type objectType) {
  239. if (node.Indexer != null) {
  240. // For indexed properties, just call the setter
  241. var method = node.Indexer.GetSetMethod(true);
  242. EmitCall(objectType, method);
  243. } else if (node.Arguments.Count != 1) {
  244. // Multidimensional arrays, call set
  245. _ilg.Emit(OpCodes.Call, node.Object.Type.GetMethod("Set", BindingFlags.Public | BindingFlags.Instance));
  246. } else {
  247. // For one dimensional arrays, emit store
  248. _ilg.EmitStoreElement(node.Type);
  249. }
  250. }
  251. #endregion
  252. #region MethodCallExpression
  253. private void EmitMethodCallExpression(Expression expr, CompilationFlags flags) {
  254. MethodCallExpression node = (MethodCallExpression)expr;
  255. EmitMethodCall(node.Object, node.Method, node, flags);
  256. }
  257. private void EmitMethodCallExpression(Expression expr) {
  258. EmitMethodCallExpression(expr, CompilationFlags.EmitAsNoTail);
  259. }
  260. private void EmitMethodCall(Expression obj, MethodInfo method, IArgumentProvider methodCallExpr) {
  261. EmitMethodCall(obj, method, methodCallExpr, CompilationFlags.EmitAsNoTail);
  262. }
  263. private void EmitMethodCall(Expression obj, MethodInfo method, IArgumentProvider methodCallExpr, CompilationFlags flags) {
  264. // Emit instance, if calling an instance method
  265. Type objectType = null;
  266. if (!method.IsStatic) {
  267. EmitInstance(obj, objectType = obj.Type);
  268. }
  269. // if the obj has a value type, its address is passed to the method call so we cannot destroy the
  270. // stack by emitting a tail call
  271. if (obj != null && obj.Type.IsValueType) {
  272. EmitMethodCall(method, methodCallExpr, objectType);
  273. } else {
  274. EmitMethodCall(method, methodCallExpr, objectType, flags);
  275. }
  276. }
  277. // assumes 'object' of non-static call is already on stack
  278. private void EmitMethodCall(MethodInfo mi, IArgumentProvider args, Type objectType) {
  279. EmitMethodCall(mi, args, objectType, CompilationFlags.EmitAsNoTail);
  280. }
  281. // assumes 'object' of non-static call is already on stack
  282. private void EmitMethodCall(MethodInfo mi, IArgumentProvider args, Type objectType, CompilationFlags flags) {
  283. // Emit arguments
  284. List<WriteBack> wb = EmitArguments(mi, args);
  285. // Emit the actual call
  286. OpCode callOp = UseVirtual(mi) ? OpCodes.Callvirt : OpCodes.Call;
  287. if (callOp == OpCodes.Callvirt && objectType.IsValueType) {
  288. // This automatically boxes value types if necessary.
  289. _ilg.Emit(OpCodes.Constrained, objectType);
  290. }
  291. // The method call can be a tail call if
  292. // 1) the method call is the last instruction before Ret
  293. // 2) the method does not have any ByRef parameters, refer to ECMA-335 Partition III Section 2.4.
  294. // "Verification requires that no managed pointers are passed to the method being called, since
  295. // it does not track pointers into the current frame."
  296. if ((flags & CompilationFlags.EmitAsTailCallMask) == CompilationFlags.EmitAsTail && !MethodHasByRefParameter(mi)) {
  297. _ilg.Emit(OpCodes.Tailcall);
  298. }
  299. if (mi.CallingConvention == CallingConventions.VarArgs) {
  300. _ilg.EmitCall(callOp, mi, args.Map(a => a.Type));
  301. } else {
  302. _ilg.Emit(callOp, mi);
  303. }
  304. // Emit writebacks for properties passed as "ref" arguments
  305. EmitWriteBack(wb);
  306. }
  307. private static bool MethodHasByRefParameter(MethodInfo mi) {
  308. foreach (var pi in mi.GetParametersCached()) {
  309. if (pi.IsByRefParameter()) {
  310. return true;
  311. }
  312. }
  313. return false;
  314. }
  315. private void EmitCall(Type objectType, MethodInfo method) {
  316. if (method.CallingConvention == CallingConventions.VarArgs) {
  317. throw Error.UnexpectedVarArgsCall(method);
  318. }
  319. OpCode callOp = UseVirtual(method) ? OpCodes.Callvirt : OpCodes.Call;
  320. if (callOp == OpCodes.Callvirt && objectType.IsValueType) {
  321. _ilg.Emit(OpCodes.Constrained, objectType);
  322. }
  323. _ilg.Emit(callOp, method);
  324. }
  325. private static bool UseVirtual(MethodInfo mi) {
  326. // There are two factors: is the method static, virtual or non-virtual instance?
  327. // And is the object ref or value?
  328. // The cases are:
  329. //
  330. // static, ref: call
  331. // static, value: call
  332. // virtual, ref: callvirt
  333. // virtual, value: call -- eg, double.ToString must be a non-virtual call to be verifiable.
  334. // instance, ref: callvirt -- this looks wrong, but is verifiable and gives us a free null check.
  335. // instance, value: call
  336. //
  337. // We never need to generate a nonvirtual call to a virtual method on a reference type because
  338. // expression trees do not support "base.Foo()" style calling.
  339. //
  340. // We could do an optimization here for the case where we know that the object is a non-null
  341. // reference type and the method is a non-virtual instance method. For example, if we had
  342. // (new Foo()).Bar() for instance method Bar we don't need the null check so we could do a
  343. // call rather than a callvirt. However that seems like it would not be a very big win for
  344. // most dynamically generated code scenarios, so let's not do that for now.
  345. if (mi.IsStatic) {
  346. return false;
  347. }
  348. if (mi.DeclaringType.IsValueType) {
  349. return false;
  350. }
  351. return true;
  352. }
  353. /// <summary>
  354. /// Emits arguments to a call, and returns an array of writebacks that
  355. /// should happen after the call.
  356. /// </summary>
  357. private List<WriteBack> EmitArguments(MethodBase method, IArgumentProvider args) {
  358. return EmitArguments(method, args, 0);
  359. }
  360. /// <summary>
  361. /// Emits arguments to a call, and returns an array of writebacks that
  362. /// should happen after the call. For emitting dynamic expressions, we
  363. /// need to skip the first parameter of the method (the call site).
  364. /// </summary>
  365. private List<WriteBack> EmitArguments(MethodBase method, IArgumentProvider args, int skipParameters) {
  366. ParameterInfo[] pis = method.GetParametersCached();
  367. Debug.Assert(args.ArgumentCount + skipParameters == pis.Length);
  368. var writeBacks = new List<WriteBack>();
  369. for (int i = skipParameters, n = pis.Length; i < n; i++) {
  370. ParameterInfo parameter = pis[i];
  371. Expression argument = args.GetArgument(i - skipParameters);
  372. Type type = parameter.ParameterType;
  373. if (type.IsByRef) {
  374. type = type.GetElementType();
  375. WriteBack wb = EmitAddressWriteBack(argument, type);
  376. if (wb != null) {
  377. writeBacks.Add(wb);
  378. }
  379. } else {
  380. EmitExpression(argument);
  381. }
  382. }
  383. return writeBacks;
  384. }
  385. private static void EmitWriteBack(IList<WriteBack> writeBacks) {
  386. foreach (WriteBack wb in writeBacks) {
  387. wb();
  388. }
  389. }
  390. #endregion
  391. private void EmitConstantExpression(Expression expr) {
  392. ConstantExpression node = (ConstantExpression)expr;
  393. EmitConstant(node.Value, node.Type);
  394. }
  395. private void EmitConstant(object value, Type type) {
  396. // Try to emit the constant directly into IL
  397. if (ILGen.CanEmitConstant(value, type)) {
  398. _ilg.EmitConstant(value, type);
  399. return;
  400. }
  401. _boundConstants.EmitConstant(this, value, type);
  402. }
  403. private void EmitDynamicExpression(Expression expr) {
  404. if (!(_method is DynamicMethod)) {
  405. throw Error.CannotCompileDynamic();
  406. }
  407. var node = (DynamicExpression)expr;
  408. var site = CallSite.Create(node.DelegateType, node.Binder);
  409. Type siteType = site.GetType();
  410. var invoke = node.DelegateType.GetMethod("Invoke");
  411. // site.Target.Invoke(site, args)
  412. EmitConstant(site, siteType);
  413. // Emit the temp as type CallSite so we get more reuse
  414. _ilg.Emit(OpCodes.Dup);
  415. #if !FEATURE_CORE_DLR
  416. // For 3.5, emit the temp as CallSite<T> to work around a Jit32
  417. // verifier issue (fixed in 3.5 sp1)
  418. var siteTemp = GetLocal(siteType);
  419. #else
  420. var siteTemp = GetLocal(typeof(CallSite));
  421. #endif
  422. _ilg.Emit(OpCodes.Stloc, siteTemp);
  423. _ilg.Emit(OpCodes.Ldfld, siteType.GetField("Target"));
  424. _ilg.Emit(OpCodes.Ldloc, siteTemp);
  425. FreeLocal(siteTemp);
  426. List<WriteBack> wb = EmitArguments(invoke, node, 1);
  427. _ilg.Emit(OpCodes.Callvirt, invoke);
  428. EmitWriteBack(wb);
  429. }
  430. private void EmitNewExpression(Expression expr) {
  431. NewExpression node = (NewExpression)expr;
  432. if (node.Constructor != null) {
  433. List<WriteBack> wb = EmitArguments(node.Constructor, node);
  434. _ilg.Emit(OpCodes.Newobj, node.Constructor);
  435. EmitWriteBack(wb);
  436. } else {
  437. Debug.Assert(node.Arguments.Count == 0, "Node with arguments must have a constructor.");
  438. Debug.Assert(node.Type.IsValueType, "Only value type may have constructor not set.");
  439. LocalBuilder temp = GetLocal(node.Type);
  440. _ilg.Emit(OpCodes.Ldloca, temp);
  441. _ilg.Emit(OpCodes.Initobj, node.Type);
  442. _ilg.Emit(OpCodes.Ldloc, temp);
  443. FreeLocal(temp);
  444. }
  445. }
  446. private void EmitTypeBinaryExpression(Expression expr) {
  447. TypeBinaryExpression node = (TypeBinaryExpression)expr;
  448. if (node.NodeType == ExpressionType.TypeEqual) {
  449. EmitExpression(node.ReduceTypeEqual());
  450. return;
  451. }
  452. Type type = node.Expression.Type;
  453. // Try to determine the result statically
  454. AnalyzeTypeIsResult result = ConstantCheck.AnalyzeTypeIs(node);
  455. if (result == AnalyzeTypeIsResult.KnownTrue ||
  456. result == AnalyzeTypeIsResult.KnownFalse) {
  457. // Result is known statically, so just emit the expression for
  458. // its side effects and return the result
  459. EmitExpressionAsVoid(node.Expression);
  460. _ilg.EmitBoolean(result == AnalyzeTypeIsResult.KnownTrue);
  461. return;
  462. }
  463. if (result == AnalyzeTypeIsResult.KnownAssignable) {
  464. // We know the type can be assigned, but still need to check
  465. // for null at runtime
  466. if (type.IsNullableType()) {
  467. EmitAddress(node.Expression, type);
  468. _ilg.EmitHasValue(type);
  469. return;
  470. }
  471. Debug.Assert(!type.IsValueType);
  472. EmitExpression(node.Expression);
  473. _ilg.Emit(OpCodes.Ldnull);
  474. _ilg.Emit(OpCodes.Ceq);
  475. _ilg.Emit(OpCodes.Ldc_I4_0);
  476. _ilg.Emit(OpCodes.Ceq);
  477. return;
  478. }
  479. Debug.Assert(result == AnalyzeTypeIsResult.Unknown);
  480. // Emit a full runtime "isinst" check
  481. EmitExpression(node.Expression);
  482. if (type.IsValueType) {
  483. _ilg.Emit(OpCodes.Box, type);
  484. }
  485. _ilg.Emit(OpCodes.Isinst, node.TypeOperand);
  486. _ilg.Emit(OpCodes.Ldnull);
  487. _ilg.Emit(OpCodes.Cgt_Un);
  488. }
  489. private void EmitVariableAssignment(BinaryExpression node, CompilationFlags flags) {
  490. var variable = (ParameterExpression)node.Left;
  491. var emitAs = flags & CompilationFlags.EmitAsTypeMask;
  492. EmitExpression(node.Right);
  493. if (emitAs != CompilationFlags.EmitAsVoidType) {
  494. _ilg.Emit(OpCodes.Dup);
  495. }
  496. if (variable.IsByRef) {
  497. // Note: the stloc/ldloc pattern is a bit suboptimal, but it
  498. // saves us from having to spill stack when assigning to a
  499. // byref parameter. We already make this same tradeoff for
  500. // hoisted variables, see ElementStorage.EmitStore
  501. LocalBuilder value = GetLocal(variable.Type);
  502. _ilg.Emit(OpCodes.Stloc, value);
  503. _scope.EmitGet(variable);
  504. _ilg.Emit(OpCodes.Ldloc, value);
  505. FreeLocal(value);
  506. _ilg.EmitStoreValueIndirect(variable.Type);
  507. } else {
  508. _scope.EmitSet(variable);
  509. }
  510. }
  511. private void EmitAssignBinaryExpression(Expression expr) {
  512. EmitAssign((BinaryExpression)expr, CompilationFlags.EmitAsDefaultType);
  513. }
  514. private void EmitAssign(BinaryExpression node, CompilationFlags emitAs) {
  515. switch (node.Left.NodeType) {
  516. case ExpressionType.Index:
  517. EmitIndexAssignment(node, emitAs);
  518. return;
  519. case ExpressionType.MemberAccess:
  520. EmitMemberAssignment(node, emitAs);
  521. return;
  522. case ExpressionType.Parameter:
  523. EmitVariableAssignment(node, emitAs);
  524. return;
  525. default:
  526. throw Error.InvalidLvalue(node.Left.NodeType);
  527. }
  528. }
  529. private void EmitParameterExpression(Expression expr) {
  530. ParameterExpression node = (ParameterExpression)expr;
  531. _scope.EmitGet(node);
  532. if (node.IsByRef) {
  533. _ilg.EmitLoadValueIndirect(node.Type);
  534. }
  535. }
  536. private void EmitLambdaExpression(Expression expr) {
  537. LambdaExpression node = (LambdaExpression)expr;
  538. EmitDelegateConstruction(node);
  539. }
  540. private void EmitRuntimeVariablesExpression(Expression expr) {
  541. RuntimeVariablesExpression node = (RuntimeVariablesExpression)expr;
  542. _scope.EmitVariableAccess(this, node.Variables);
  543. }
  544. private void EmitMemberAssignment(BinaryExpression node, CompilationFlags flags) {
  545. MemberExpression lvalue = (MemberExpression)node.Left;
  546. MemberInfo member = lvalue.Member;
  547. // emit "this", if any
  548. Type objectType = null;
  549. if (lvalue.Expression != null) {
  550. EmitInstance(lvalue.Expression, objectType = lvalue.Expression.Type);
  551. }
  552. // emit value
  553. EmitExpression(node.Right);
  554. LocalBuilder temp = null;
  555. var emitAs = flags & CompilationFlags.EmitAsTypeMask;
  556. if (emitAs != CompilationFlags.EmitAsVoidType) {
  557. // save the value so we can return it
  558. _ilg.Emit(OpCodes.Dup);
  559. _ilg.Emit(OpCodes.Stloc, temp = GetLocal(node.Type));
  560. }
  561. switch (member.MemberType) {
  562. case MemberTypes.Field:
  563. _ilg.EmitFieldSet((FieldInfo)member);
  564. break;
  565. case MemberTypes.Property:
  566. EmitCall(objectType, ((PropertyInfo)member).GetSetMethod(true));
  567. break;
  568. default:
  569. throw Error.InvalidMemberType(member.MemberType);
  570. }
  571. if (emitAs != CompilationFlags.EmitAsVoidType) {
  572. _ilg.Emit(OpCodes.Ldloc, temp);
  573. FreeLocal(temp);
  574. }
  575. }
  576. private void EmitMemberExpression(Expression expr) {
  577. MemberExpression node = (MemberExpression)expr;
  578. // emit "this", if any
  579. Type instanceType = null;
  580. if (node.Expression != null) {
  581. EmitInstance(node.Expression, instanceType = node.Expression.Type);
  582. }
  583. EmitMemberGet(node.Member, instanceType);
  584. }
  585. // assumes instance is already on the stack
  586. private void EmitMemberGet(MemberInfo member, Type objectType) {
  587. switch (member.MemberType) {
  588. case MemberTypes.Field:
  589. FieldInfo fi = (FieldInfo)member;
  590. if (fi.IsLiteral) {
  591. EmitConstant(fi.GetRawConstantValue(), fi.FieldType);
  592. } else {
  593. _ilg.EmitFieldGet(fi);
  594. }
  595. break;
  596. case MemberTypes.Property:
  597. EmitCall(objectType, ((PropertyInfo)member).GetGetMethod(true));
  598. break;
  599. default:
  600. throw ContractUtils.Unreachable;
  601. }
  602. }
  603. private void EmitInstance(Expression instance, Type type) {
  604. if (instance != null) {
  605. if (type.IsValueType) {
  606. EmitAddress(instance, type);
  607. } else {
  608. EmitExpression(instance);
  609. }
  610. }
  611. }
  612. private void EmitNewArrayExpression(Expression expr) {
  613. NewArrayExpression node = (NewArrayExpression)expr;
  614. if (node.NodeType == ExpressionType.NewArrayInit) {
  615. _ilg.EmitArray(
  616. node.Type.GetElementType(),
  617. node.Expressions.Count,
  618. delegate(int index) {
  619. EmitExpression(node.Expressions[index]);
  620. }
  621. );
  622. } else {
  623. ReadOnlyCollection<Expression> bounds = node.Expressions;
  624. for (int i = 0; i < bounds.Count; i++) {
  625. Expression x = bounds[i];
  626. EmitExpression(x);
  627. _ilg.EmitConvertToType(x.Type, typeof(int), true);
  628. }
  629. _ilg.EmitArray(node.Type);
  630. }
  631. }
  632. private void EmitDebugInfoExpression(Expression expr) {
  633. if (!EmitDebugSymbols) {
  634. return;
  635. }
  636. var node = (DebugInfoExpression)expr;
  637. if (node.IsClear && _sequencePointCleared) {
  638. // Emitting another clearance after one clearance does not
  639. // have any effect, so we can save it.
  640. return;
  641. }
  642. _tree.DebugInfoGenerator.MarkSequencePoint(_lambda, _method, _ilg, node);
  643. _ilg.Emit(OpCodes.Nop);
  644. _sequencePointCleared = node.IsClear;
  645. }
  646. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "expr")]
  647. private static void EmitExtensionExpression(Expression expr) {
  648. throw Error.ExtensionNotReduced();
  649. }
  650. #region ListInit, MemberInit
  651. private void EmitListInitExpression(Expression expr) {
  652. EmitListInit((ListInitExpression)expr);
  653. }
  654. private void EmitMemberInitExpression(Expression expr) {
  655. EmitMemberInit((MemberInitExpression)expr);
  656. }
  657. private void EmitBinding(MemberBinding binding, Type objectType) {
  658. switch (binding.BindingType) {
  659. case MemberBindingType.Assignment:
  660. EmitMemberAssignment((MemberAssignment)binding, objectType);
  661. break;
  662. case MemberBindingType.ListBinding:
  663. EmitMemberListBinding((MemberListBinding)binding);
  664. break;
  665. case MemberBindingType.MemberBinding:
  666. EmitMemberMemberBinding((MemberMemberBinding)binding);
  667. break;
  668. default:
  669. throw Error.UnknownBindingType();
  670. }
  671. }
  672. private void EmitMemberAssignment(MemberAssignment binding, Type objectType) {
  673. EmitExpression(binding.Expression);
  674. FieldInfo fi = binding.Member as FieldInfo;
  675. if (fi != null) {
  676. _ilg.Emit(OpCodes.Stfld, fi);
  677. } else {
  678. PropertyInfo pi = binding.Member as PropertyInfo;
  679. if (pi != null) {
  680. EmitCall(objectType, pi.GetSetMethod(true));
  681. } else {
  682. throw Error.UnhandledBinding();
  683. }
  684. }
  685. }
  686. private void EmitMemberMemberBinding(MemberMemberBinding binding) {
  687. Type type = GetMemberType(binding.Member);
  688. if (binding.Member is PropertyInfo && type.IsValueType) {
  689. throw Error.CannotAutoInitializeValueTypeMemberThroughProperty(binding.Member);
  690. }
  691. if (type.IsValueType) {
  692. EmitMemberAddress(binding.Member, binding.Member.DeclaringType);
  693. } else {
  694. EmitMemberGet(binding.Member, binding.Member.DeclaringType);
  695. }
  696. EmitMemberInit(binding.Bindings, false, type);
  697. }
  698. private void EmitMemberListBinding(MemberListBinding binding) {
  699. Type type = GetMemberType(binding.Member);
  700. if (binding.Member is PropertyInfo && type.IsValueType) {
  701. throw Error.CannotAutoInitializeValueTypeElementThroughProperty(binding.Member);
  702. }
  703. if (type.IsValueType) {
  704. EmitMemberAddress(binding.Member, binding.Member.DeclaringType);
  705. } else {
  706. EmitMemberGet(binding.Member, binding.Member.DeclaringType);
  707. }
  708. EmitListInit(binding.Initializers, false, type);
  709. }
  710. private void EmitMemberInit(MemberInitExpression init) {
  711. EmitExpression(init.NewExpression);
  712. LocalBuilder loc = null;
  713. if (init.NewExpression.Type.IsValueType && init.Bindings.Count > 0) {
  714. loc = _ilg.DeclareLocal(init.NewExpression.Type);
  715. _ilg.Emit(OpCodes.Stloc, loc);
  716. _ilg.Emit(OpCodes.Ldloca, loc);
  717. }
  718. EmitMemberInit(init.Bindings, loc == null, init.NewExpression.Type);
  719. if (loc != null) {
  720. _ilg.Emit(OpCodes.Ldloc, loc);
  721. }
  722. }
  723. // This method assumes that the instance is on the stack and is expected, based on "keepOnStack" flag
  724. // to either leave the instance on the stack, or pop it.
  725. private void EmitMemberInit(ReadOnlyCollection<MemberBinding> bindings, bool keepOnStack, Type objectType) {
  726. int n = bindings.Count;
  727. if (n == 0) {
  728. // If there are no initializers and instance is not to be kept on the stack, we must pop explicitly.
  729. if (!keepOnStack) {
  730. _ilg.Emit(OpCodes.Pop);
  731. }
  732. } else {
  733. for (int i = 0; i < n; i++) {
  734. if (keepOnStack || i < n - 1) {
  735. _ilg.Emit(OpCodes.Dup);
  736. }
  737. EmitBinding(bindings[i], objectType);
  738. }
  739. }
  740. }
  741. private void EmitListInit(ListInitExpression init) {
  742. EmitExpression(init.NewExpression);
  743. LocalBuilder loc = null;
  744. if (init.NewExpression.Type.IsValueType) {
  745. loc = _ilg.DeclareLocal(init.NewExpression.Type);
  746. _ilg.Emit(OpCodes.Stloc, loc);
  747. _ilg.Emit(OpCodes.Ldloca, loc);
  748. }
  749. EmitListInit(init.Initializers, loc == null, init.NewExpression.Type);
  750. if (loc != null) {
  751. _ilg.Emit(OpCodes.Ldloc, loc);
  752. }
  753. }
  754. // This method assumes that the list instance is on the stack and is expected, based on "keepOnStack" flag
  755. // to either leave the list instance on the stack, or pop it.
  756. private void EmitListInit(ReadOnlyCollection<ElementInit> initializers, bool keepOnStack, Type objectType) {
  757. int n = initializers.Count;
  758. if (n == 0) {
  759. // If there are no initializers and instance is not to be kept on the stack, we must pop explicitly.
  760. if (!keepOnStack) {
  761. _ilg.Emit(OpCodes.Pop);
  762. }
  763. } else {
  764. for (int i = 0; i < n; i++) {
  765. if (keepOnStack || i < n - 1) {
  766. _ilg.Emit(OpCodes.Dup);
  767. }
  768. EmitMethodCall(initializers[i].AddMethod, initializers[i], objectType);
  769. // Aome add methods, ArrayList.Add for example, return non-void
  770. if (initializers[i].AddMethod.ReturnType != typeof(void)) {
  771. _ilg.Emit(OpCodes.Pop);
  772. }
  773. }
  774. }
  775. }
  776. private static Type GetMemberType(MemberInfo member) {
  777. FieldInfo fi = member as FieldInfo;
  778. if (fi != null) return fi.FieldType;
  779. PropertyInfo pi = member as PropertyInfo;
  780. if (pi != null) return pi.PropertyType;
  781. throw Error.MemberNotFieldOrProperty(member);
  782. }
  783. #endregion
  784. #region Expression helpers
  785. internal static void ValidateLift(IList<ParameterExpression> variables, IList<Expression> arguments) {
  786. System.Diagnostics.Debug.Assert(variables != null);
  787. System.Diagnostics.Debug.Assert(arguments != null);
  788. if (variables.Count != arguments.Count) {
  789. throw Error.IncorrectNumberOfIndexes();
  790. }
  791. for (int i = 0, n = variables.Count; i < n; i++) {
  792. if (!TypeUtils.AreReferenceAssignable(variables[i].Type, TypeUtils.GetNonNullableType(arguments[i].Type))) {
  793. throw Error.ArgumentTypesMustMatch();
  794. }
  795. }
  796. }
  797. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  798. private void EmitLift(ExpressionType nodeType, Type resultType, MethodCallExpression mc, ParameterExpression[] paramList, Expression[] argList) {
  799. Debug.Assert(TypeUtils.AreEquivalent(TypeUtils.GetNonNullableType(resultType), TypeUtils.GetNonNullableType(mc.Type)));
  800. switch (nodeType) {
  801. default:
  802. case ExpressionType.LessThan:
  803. case ExpressionType.LessThanOrEqual:
  804. case ExpressionType.GreaterThan:
  805. case ExpressionType.GreaterThanOrEqual: {
  806. Label exit = _ilg.DefineLabel();
  807. Label exitNull = _ilg.DefineLabel();
  808. LocalBuilder anyNull = _ilg.DeclareLocal(typeof(bool));
  809. for (int i = 0, n = paramList.Length; i < n; i++) {
  810. ParameterExpression v = paramList[i];
  811. Expression arg = argList[i];
  812. if (TypeUtils.IsNullableType(arg.Type)) {
  813. _scope.AddLocal(this, v);
  814. EmitAddress(arg, arg.Type);
  815. _ilg.Emit(OpCodes.Dup);
  816. _ilg.EmitHasValue(arg.Type);
  817. _ilg.Emit(OpCodes.Ldc_I4_0);
  818. _ilg.Emit(OpCodes.Ceq);
  819. _ilg.Emit(OpCodes.Stloc, anyNull);
  820. _ilg.EmitGetValueOrDefault(arg.Type);
  821. _scope.EmitSet(v);
  822. } else {
  823. _scope.AddLocal(this, v);
  824. EmitExpression(arg);
  825. if (!arg.Type.IsValueType) {
  826. _ilg.Emit(OpCodes.Dup);
  827. _ilg.Emit(OpCodes.Ldnull);
  828. _ilg.Emit(OpCodes.Ceq);
  829. _ilg.Emit(OpCodes.Stloc, anyNull);
  830. }
  831. _scope.EmitSet(v);
  832. }
  833. _ilg.Emit(OpCodes.Ldloc, anyNull);
  834. _ilg.Emit(OpCodes.Brtrue, exitNull);
  835. }
  836. EmitMethodCallExpression(mc);
  837. if (TypeUtils.IsNullableType(resultType) && !TypeUtils.AreEquivalent(resultType, mc.Type)) {
  838. ConstructorInfo ci = resultType.GetConstructor(new Type[] { mc.Type });
  839. _ilg.Emit(OpCodes.Newobj, ci);
  840. }
  841. _ilg.Emit(OpCodes.Br_S, exit);
  842. _ilg.MarkLabel(exitNull);
  843. if (TypeUtils.AreEquivalent(resultType, TypeUtils.GetNullableType(mc.Type))) {
  844. if (resultType.IsValueType) {
  845. LocalBuilder result = GetLocal(resultType);
  846. _ilg.Emit(OpCodes.Ldloca, result);
  847. _ilg.Emit(OpCodes.Initobj, resultType);
  848. _ilg.Emit(OpCodes.Ldloc, result);
  849. FreeLocal(result);
  850. } else {
  851. _ilg.Emit(OpCodes.Ldnull);
  852. }
  853. } else {
  854. switch (nodeType) {
  855. case ExpressionType.LessThan:
  856. case ExpressionType.LessThanOrEqual:
  857. case ExpressionType.GreaterThan:
  858. case ExpressionType.GreaterThanOrEqual:
  859. _ilg.Emit(OpCodes.Ldc_I4_0);
  860. break;
  861. default:
  862. throw Error.UnknownLiftType(nodeType);
  863. }
  864. }
  865. _ilg.MarkLabel(exit);
  866. return;
  867. }
  868. case ExpressionType.Equal:
  869. case ExpressionType.NotEqual: {
  870. if (TypeUtils.AreEquivalent(resultType, TypeUtils.GetNullableType(mc.Type))) {
  871. goto default;
  872. }
  873. Label exit = _ilg.DefineLabel();
  874. Label exitAllNull = _ilg.DefineLabel();
  875. Label exitAnyNull = _ilg.DefineLabel();
  876. LocalBuilder anyNull = _ilg.DeclareLocal(typeof(bool));
  877. LocalBuilder allNull = _ilg.DeclareLocal(typeof(bool));
  878. _ilg.Emit(OpCodes.Ldc_I4_0);
  879. _ilg.Emit(OpCodes.Stloc, anyNull);
  880. _ilg.Emit(OpCodes.Ldc_I4_1);
  881. _ilg.Emit(OpCodes.Stloc, allNull);
  882. for (int i = 0, n = paramList.Length; i < n; i++) {
  883. ParameterExpression v = paramList[i];
  884. Expression arg = argList[i];
  885. _scope.AddLocal(this, v);
  886. if (TypeUtils.IsNullableType(arg.Type)) {
  887. EmitAddress(arg, arg.Type);
  888. _ilg.Emit(OpCodes.Dup);
  889. _ilg.EmitHasValue(arg.Type);
  890. _ilg.Emit(OpCodes.Ldc_I4_0);
  891. _ilg.Emit(OpCodes.Ceq);
  892. _ilg.Emit(OpCodes.Dup);
  893. _ilg.Emit(OpCodes.Ldloc, anyNull);
  894. _ilg.Emit(OpCodes.Or);
  895. _ilg.Emit(OpCodes.Stloc, anyNull);
  896. _ilg.Emit(OpCodes.Ldloc, allNull);
  897. _ilg.Emit(OpCodes.And);
  898. _ilg.Emit(OpCodes.Stloc, allNull);
  899. _ilg.EmitGetValueOrDefault(arg.Type);
  900. } else {
  901. EmitExpression(arg);
  902. if (!arg.Type.IsValueType) {
  903. _ilg.Emit(OpCodes.Dup);
  904. _ilg.Emit(OpCodes.Ldnull);
  905. _ilg.Emit(OpCodes.Ceq);
  906. _ilg.Emit(OpCodes.Dup);
  907. _ilg.Emit(OpCodes.Ldloc, anyNull);
  908. _ilg.Emit(OpCodes.Or);
  909. _ilg.Emit(OpCodes.Stloc, anyNull);
  910. _ilg.Emit(OpCodes.Ldloc, allNull);
  911. _ilg.Emit(OpCodes.And);
  912. _ilg.Emit(OpCodes.Stloc, allNull);
  913. } else {
  914. _ilg.Emit(OpCodes.Ldc_I4_0);
  915. _ilg.Emit(OpCodes.Stloc, allNull);
  916. }
  917. }
  918. _scope.EmitSet(v);
  919. }
  920. _ilg.Emit(OpCodes.Ldloc, allNull);
  921. _ilg.Emit(OpCodes.Brtrue, exitAllNull);
  922. _ilg.Emit(OpCodes.Ldloc, anyNull);
  923. _ilg.Emit(OpCodes.Brtrue, exitAnyNull);
  924. EmitMethodCallExpression(mc);
  925. if (TypeUtils.IsNullableType(resultType) && !TypeUtils.AreEquivalent(resultType, mc.Type)) {
  926. ConstructorInfo ci = resultType.GetConstructor(new Type[] { mc.Type });
  927. _ilg.Emit(OpCodes.Newobj, ci);
  928. }
  929. _ilg.Emit(OpCodes.Br_S, exit);
  930. _ilg.MarkLabel(exitAllNull);
  931. _ilg.EmitBoolean(nodeType == ExpressionType.Equal);
  932. _ilg.Emit(OpCodes.Br_S, exit);
  933. _ilg.MarkLabel(exitAnyNull);
  934. _ilg.EmitBoolean(nodeType == ExpressionType.NotEqual);
  935. _ilg.MarkLabel(exit);
  936. return;
  937. }
  938. }
  939. }
  940. #endregion
  941. }
  942. }