1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
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.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using System.Linq.Expressions;
18 using Microsoft.Scripting.Ast;
20 using Microsoft.Scripting.Ast;
25 using System.Collections.Generic;
26 using System.Diagnostics;
27 using System.Reflection;
28 using System.Runtime.CompilerServices;
30 using System.Reflection.Emit;
33 using AstUtils = Microsoft.Scripting.Ast.Utils;
34 using Microsoft.Scripting.Utils;
35 using Microsoft.Scripting.Runtime;
36 using System.Security;
38 namespace Microsoft.Scripting.Interpreter {
39 public sealed class ExceptionHandler {
40 public readonly Type ExceptionType;
41 public readonly int StartIndex;
42 public readonly int EndIndex;
43 public readonly int LabelIndex;
44 public readonly int HandlerStartIndex;
46 public bool IsFault { get { return ExceptionType == null; } }
48 internal ExceptionHandler(int start, int end, int labelIndex, int handlerStartIndex, Type exceptionType) {
51 LabelIndex = labelIndex;
52 ExceptionType = exceptionType;
53 HandlerStartIndex = handlerStartIndex;
56 public bool Matches(Type exceptionType, int index) {
57 if (index >= StartIndex && index < EndIndex) {
58 if (ExceptionType == null || ExceptionType.IsAssignableFrom(exceptionType)) {
65 public bool IsBetterThan(ExceptionHandler other) {
66 if (other == null) return true;
68 if (StartIndex == other.StartIndex && EndIndex == other.EndIndex) {
69 return HandlerStartIndex < other.HandlerStartIndex;
72 if (StartIndex > other.StartIndex) {
73 Debug.Assert(EndIndex <= other.EndIndex);
75 } else if (EndIndex < other.EndIndex) {
76 Debug.Assert(StartIndex == other.StartIndex);
83 internal bool IsInside(int index) {
84 return index >= StartIndex && index < EndIndex;
87 public override string ToString() {
88 return String.Format("{0} [{1}-{2}] [{3}->]",
89 (IsFault ? "fault" : "catch(" + ExceptionType.Name + ")"),
97 public class DebugInfo {
100 public int StartLine, EndLine;
102 public string FileName;
104 private static readonly DebugInfoComparer _debugComparer = new DebugInfoComparer();
106 private class DebugInfoComparer : IComparer<DebugInfo> {
107 //We allow comparison between int and DebugInfo here
108 int IComparer<DebugInfo>.Compare(DebugInfo d1, DebugInfo d2) {
109 if (d1.Index > d2.Index) return 1;
110 else if (d1.Index == d2.Index) return 0;
115 public static DebugInfo GetMatchingDebugInfo(DebugInfo[] debugInfos, int index) {
116 //Create a faked DebugInfo to do the search
117 DebugInfo d = new DebugInfo { Index = index };
119 //to find the closest debug info before the current index
121 int i = Array.BinarySearch<DebugInfo>(debugInfos, d, _debugComparer);
123 //~i is the index for the first bigger element
124 //if there is no bigger element, ~i is the length of the array
129 //return the last one that is smaller
133 return debugInfos[i];
136 public override string ToString() {
138 return String.Format("{0}: clear", Index);
140 return String.Format("{0}: [{1}-{2}] '{3}'", Index, StartLine, EndLine, FileName);
146 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")]
148 public struct InterpretedFrameInfo {
149 public readonly string MethodName;
152 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
153 public readonly DebugInfo DebugInfo;
155 public InterpretedFrameInfo(string methodName, DebugInfo info) {
156 MethodName = methodName;
160 public override string ToString() {
161 return MethodName + (DebugInfo != null ? ": " + DebugInfo.ToString() : null);
165 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
166 public sealed class LightCompiler {
167 internal const int DefaultCompilationThreshold = 32;
169 // zero: sync compilation
170 private readonly int _compilationThreshold;
172 private readonly InstructionList _instructions;
173 private readonly LocalVariables _locals = new LocalVariables();
175 private readonly List<ExceptionHandler> _handlers = new List<ExceptionHandler>();
177 private readonly List<DebugInfo> _debugInfos = new List<DebugInfo>();
178 private readonly HybridReferenceDictionary<LabelTarget, LabelInfo> _treeLabels = new HybridReferenceDictionary<LabelTarget, LabelInfo>();
179 private LabelScopeInfo _labelBlock = new LabelScopeInfo(null, LabelScopeKind.Lambda);
181 private readonly Stack<ParameterExpression> _exceptionForRethrowStack = new Stack<ParameterExpression>();
183 // Set to true to force compiliation of this lambda.
184 // This disables the interpreter for this lambda. We still need to
185 // walk it, however, to resolve variables closed over from the parent
186 // lambdas (because they may be interpreted).
187 private bool _forceCompile;
189 private readonly LightCompiler _parent;
191 private static LocalDefinition[] EmptyLocals = new LocalDefinition[0];
193 internal LightCompiler(int compilationThreshold) {
194 _instructions = new InstructionList();
195 _compilationThreshold = compilationThreshold < 0 ? DefaultCompilationThreshold : compilationThreshold;
198 private LightCompiler(LightCompiler parent)
199 : this(parent._compilationThreshold) {
203 public InstructionList Instructions {
204 get { return _instructions; }
207 public LocalVariables Locals {
208 get { return _locals; }
211 internal static Expression Unbox(Expression strongBoxExpression) {
212 return Expression.Field(strongBoxExpression, typeof(StrongBox<object>).GetDeclaredField("Value"));
215 internal LightDelegateCreator CompileTop(LambdaExpression node) {
216 foreach (var p in node.Parameters) {
217 var local = _locals.DefineLocal(p, 0);
218 _instructions.EmitInitializeParameter(local.Index);
223 // pop the result of the last expression:
224 if (node.Body.Type != typeof(void) && node.ReturnType == typeof(void)) {
225 _instructions.EmitPop();
228 Debug.Assert(_instructions.CurrentStackDepth == (node.ReturnType != typeof(void) ? 1 : 0));
230 return new LightDelegateCreator(MakeInterpreter(node.Name), node);
233 internal LightDelegateCreator CompileTop(LightLambdaExpression node) {
234 foreach (var p in node.Parameters) {
235 var local = _locals.DefineLocal(p, 0);
236 _instructions.EmitInitializeParameter(local.Index);
241 // pop the result of the last expression:
242 if (node.Body.Type != typeof(void) && node.ReturnType == typeof(void)) {
243 _instructions.EmitPop();
246 Debug.Assert(_instructions.CurrentStackDepth == (node.ReturnType != typeof(void) ? 1 : 0));
248 return new LightDelegateCreator(MakeInterpreter(node.Name), node);
251 private Interpreter MakeInterpreter(string lambdaName) {
256 var handlers = _handlers.ToArray();
257 var debugInfos = _debugInfos.ToArray();
259 return new Interpreter(lambdaName, _locals, GetBranchMapping(), _instructions.ToArray(), handlers, debugInfos, _compilationThreshold);
263 private void CompileConstantExpression(Expression expr) {
264 var node = (ConstantExpression)expr;
265 _instructions.EmitLoad(node.Value, node.Type);
268 private void CompileDefaultExpression(Expression expr) {
269 CompileDefaultExpression(expr.Type);
272 private void CompileDefaultExpression(Type type) {
273 if (type != typeof(void)) {
274 if (type.IsValueType()) {
275 object value = ScriptingRuntimeHelpers.GetPrimitiveDefaultValue(type);
277 _instructions.EmitLoad(value);
279 _instructions.EmitDefaultValue(type);
282 _instructions.EmitLoad(null);
287 private LocalVariable EnsureAvailableForClosure(ParameterExpression expr) {
289 if (_locals.TryGetLocalOrClosure(expr, out local)) {
290 if (!local.InClosure && !local.IsBoxed) {
291 _locals.Box(expr, _instructions);
294 } else if (_parent != null) {
295 _parent.EnsureAvailableForClosure(expr);
296 return _locals.AddClosureVariable(expr);
298 throw new InvalidOperationException("unbound variable: " + expr);
302 private void EnsureVariable(ParameterExpression variable) {
303 if (!_locals.ContainsVariable(variable)) {
304 EnsureAvailableForClosure(variable);
308 private LocalVariable ResolveLocal(ParameterExpression variable) {
310 if (!_locals.TryGetLocalOrClosure(variable, out local)) {
311 local = EnsureAvailableForClosure(variable);
316 public void CompileGetVariable(ParameterExpression variable) {
317 LocalVariable local = ResolveLocal(variable);
319 if (local.InClosure) {
320 _instructions.EmitLoadLocalFromClosure(local.Index);
321 } else if (local.IsBoxed) {
322 _instructions.EmitLoadLocalBoxed(local.Index);
324 _instructions.EmitLoadLocal(local.Index);
327 _instructions.SetDebugCookie(variable.Name);
330 public void CompileGetBoxedVariable(ParameterExpression variable) {
331 LocalVariable local = ResolveLocal(variable);
333 if (local.InClosure) {
334 _instructions.EmitLoadLocalFromClosureBoxed(local.Index);
336 Debug.Assert(local.IsBoxed);
337 _instructions.EmitLoadLocal(local.Index);
340 _instructions.SetDebugCookie(variable.Name);
343 public void CompileSetVariable(ParameterExpression variable, bool isVoid) {
344 LocalVariable local = ResolveLocal(variable);
346 if (local.InClosure) {
348 _instructions.EmitStoreLocalToClosure(local.Index);
350 _instructions.EmitAssignLocalToClosure(local.Index);
352 } else if (local.IsBoxed) {
354 _instructions.EmitStoreLocalBoxed(local.Index);
356 _instructions.EmitAssignLocalBoxed(local.Index);
360 _instructions.EmitStoreLocal(local.Index);
362 _instructions.EmitAssignLocal(local.Index);
366 _instructions.SetDebugCookie(variable.Name);
369 public void CompileParameterExpression(Expression expr) {
370 var node = (ParameterExpression)expr;
371 CompileGetVariable(node);
374 private void CompileBlockExpression(Expression expr, bool asVoid) {
375 var node = (BlockExpression)expr;
376 var end = CompileBlockStart(node);
378 var lastExpression = node.Expressions[node.Expressions.Count - 1];
379 Compile(lastExpression, asVoid);
380 CompileBlockEnd(end);
383 private LocalDefinition[] CompileBlockStart(BlockExpression node) {
384 var start = _instructions.Count;
386 LocalDefinition[] locals;
387 var variables = node.Variables;
388 if (variables.Count != 0) {
389 // TODO: basic flow analysis so we don't have to initialize all
391 locals = new LocalDefinition[variables.Count];
393 foreach (var variable in variables) {
394 var local = _locals.DefineLocal(variable, start);
395 locals[localCnt++] = local;
397 _instructions.EmitInitializeLocal(local.Index, variable.Type);
398 _instructions.SetDebugCookie(variable.Name);
401 locals = EmptyLocals;
404 for (int i = 0; i < node.Expressions.Count - 1; i++) {
405 CompileAsVoid(node.Expressions[i]);
410 private void CompileBlockEnd(LocalDefinition[] locals) {
411 foreach (var local in locals) {
412 _locals.UndefineLocal(local, _instructions.Count);
416 private void CompileIndexExpression(Expression expr) {
417 var index = (IndexExpression)expr;
420 if (index.Object != null) {
421 Compile(index.Object);
424 // indexes, byref args not allowed.
425 foreach (var arg in index.Arguments) {
429 if (index.Indexer != null) {
430 EmitCall(index.Indexer.GetGetMethod(true));
431 } else if (index.Arguments.Count != 1) {
432 EmitCall(index.Object.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance));
434 _instructions.EmitGetArrayItem(index.Object.Type);
438 private void CompileIndexAssignment(BinaryExpression node, bool asVoid) {
439 var index = (IndexExpression)node.Left;
442 throw new NotImplementedException();
446 if (index.Object != null) {
447 Compile(index.Object);
450 // indexes, byref args not allowed.
451 foreach (var arg in index.Arguments) {
458 if (index.Indexer != null) {
459 EmitCall(index.Indexer.GetSetMethod(true));
460 } else if (index.Arguments.Count != 1) {
461 EmitCall(index.Object.Type.GetMethod("Set", BindingFlags.Public | BindingFlags.Instance));
463 _instructions.EmitSetArrayItem(index.Object.Type);
467 private void CompileMemberAssignment(BinaryExpression node, bool asVoid) {
468 var member = (MemberExpression)node.Left;
470 PropertyInfo pi = member.Member as PropertyInfo;
472 var method = pi.GetSetMethod(true);
473 Compile(member.Expression);
476 int start = _instructions.Count;
478 LocalDefinition local = _locals.DefineLocal(Expression.Parameter(node.Right.Type), start);
479 _instructions.EmitAssignLocal(local.Index);
481 _instructions.EmitLoadLocal(local.Index);
482 _locals.UndefineLocal(local, _instructions.Count);
489 FieldInfo fi = member.Member as FieldInfo;
491 if (member.Expression != null) {
492 Compile(member.Expression);
496 int start = _instructions.Count;
498 LocalDefinition local = _locals.DefineLocal(Expression.Parameter(node.Right.Type), start);
499 _instructions.EmitAssignLocal(local.Index);
500 _instructions.EmitStoreField(fi);
501 _instructions.EmitLoadLocal(local.Index);
502 _locals.UndefineLocal(local, _instructions.Count);
504 _instructions.EmitStoreField(fi);
509 throw new NotImplementedException();
512 private void CompileVariableAssignment(BinaryExpression node, bool asVoid) {
513 this.Compile(node.Right);
515 var target = (ParameterExpression)node.Left;
516 CompileSetVariable(target, asVoid);
519 private void CompileAssignBinaryExpression(Expression expr, bool asVoid) {
520 var node = (BinaryExpression)expr;
522 switch (node.Left.NodeType) {
523 case ExpressionType.Index:
524 CompileIndexAssignment(node, asVoid);
527 case ExpressionType.MemberAccess:
528 CompileMemberAssignment(node, asVoid);
531 case ExpressionType.Parameter:
532 case ExpressionType.Extension:
533 CompileVariableAssignment(node, asVoid);
537 throw new InvalidOperationException("Invalid lvalue for assignment: " + node.Left.NodeType);
541 private void CompileBinaryExpression(Expression expr) {
542 var node = (BinaryExpression)expr;
544 if (node.Method != null) {
547 EmitCall(node.Method);
549 switch (node.NodeType) {
550 case ExpressionType.ArrayIndex:
551 Debug.Assert(node.Right.Type == typeof(int));
554 _instructions.EmitGetArrayItem(node.Left.Type);
557 case ExpressionType.Add:
558 case ExpressionType.AddChecked:
559 case ExpressionType.Subtract:
560 case ExpressionType.SubtractChecked:
561 case ExpressionType.Multiply:
562 case ExpressionType.MultiplyChecked:
563 case ExpressionType.Divide:
564 case ExpressionType.Modulo:
565 CompileArithmetic(node.NodeType, node.Left, node.Right);
568 case ExpressionType.Equal:
569 CompileEqual(node.Left, node.Right, node.IsLiftedToNull);
572 case ExpressionType.NotEqual:
573 CompileNotEqual(node.Left, node.Right, node.IsLiftedToNull);
576 case ExpressionType.LessThan:
577 case ExpressionType.LessThanOrEqual:
578 case ExpressionType.GreaterThan:
579 case ExpressionType.GreaterThanOrEqual:
580 CompileComparison(node.NodeType, node.Left, node.Right, node.IsLiftedToNull);
583 case ExpressionType.LeftShift:
584 case ExpressionType.RightShift:
585 CompileShift(node.NodeType, node.Left, node.Right, node.IsLifted);
588 case ExpressionType.And:
589 case ExpressionType.Or:
590 case ExpressionType.ExclusiveOr:
591 CompileLogical(node.NodeType, node.Left, node.Right, node.IsLifted);
595 throw new NotImplementedException(node.NodeType.ToString());
600 private void CompileEqual(Expression left, Expression right, bool liftedResult) {
601 Debug.Assert(left.Type == right.Type || !left.Type.IsValueType() && !right.Type.IsValueType());
604 _instructions.EmitEqual(left.Type, liftedResult);
607 private void CompileNotEqual(Expression left, Expression right, bool liftedResult) {
608 Debug.Assert(left.Type == right.Type || !left.Type.IsValueType() && !right.Type.IsValueType());
611 _instructions.EmitNotEqual(left.Type, liftedResult);
614 private void CompileComparison(ExpressionType nodeType, Expression left, Expression right, bool liftedResult) {
615 Debug.Assert(left.Type == right.Type && TypeUtils.IsNumeric(left.Type));
621 case ExpressionType.LessThan: _instructions.EmitLessThan(left.Type, liftedResult); break;
622 case ExpressionType.LessThanOrEqual: _instructions.EmitLessThanOrEqual(left.Type, liftedResult); break;
623 case ExpressionType.GreaterThan: _instructions.EmitGreaterThan(left.Type, liftedResult); break;
624 case ExpressionType.GreaterThanOrEqual: _instructions.EmitGreaterThanOrEqual(left.Type, liftedResult); break;
625 default: throw Assert.Unreachable;
629 private void CompileArithmetic(ExpressionType nodeType, Expression left, Expression right) {
630 Debug.Assert(left.Type == right.Type && TypeUtils.IsArithmetic(left.Type));
634 case ExpressionType.Add: _instructions.EmitAdd(left.Type, false); break;
635 case ExpressionType.AddChecked: _instructions.EmitAdd(left.Type, true); break;
636 case ExpressionType.Subtract: _instructions.EmitSub(left.Type, false); break;
637 case ExpressionType.SubtractChecked: _instructions.EmitSub(left.Type, true); break;
638 case ExpressionType.Multiply: _instructions.EmitMul(left.Type, false); break;
639 case ExpressionType.MultiplyChecked: _instructions.EmitMul(left.Type, true); break;
640 case ExpressionType.Divide: _instructions.EmitDiv(left.Type); break;
641 case ExpressionType.Modulo: _instructions.EmitMod(left.Type); break;
642 default: throw Assert.Unreachable;
646 private void CompileShift(ExpressionType nodeType, Expression left, Expression right, bool lifted) {
647 Debug.Assert(right.Type == typeof (int) || right.Type == typeof (int?));
651 case ExpressionType.LeftShift: _instructions.EmitShl(TypeUtils.GetNonNullableType (left.Type), lifted); break;
652 case ExpressionType.RightShift: _instructions.EmitShr(TypeUtils.GetNonNullableType (left.Type), lifted); break;
653 default: throw Assert.Unreachable;
657 private void CompileLogical(ExpressionType nodeType, Expression left, Expression right, bool lifted) {
658 Debug.Assert(left.Type == right.Type); // && TypeUtils.IsIntegerOrBool(left.Type));
662 case ExpressionType.And: _instructions.EmitAnd(TypeUtils.GetNonNullableType (left.Type), lifted); break;
663 case ExpressionType.Or: _instructions.EmitOr(TypeUtils.GetNonNullableType (left.Type), lifted); break;
664 case ExpressionType.ExclusiveOr: _instructions.EmitExclusiveOr(TypeUtils.GetNonNullableType (left.Type), lifted); break;
665 default: throw Assert.Unreachable;
669 private void CompileConvertUnaryExpression(Expression expr) {
670 var node = (UnaryExpression)expr;
671 if (node.Method != null) {
672 Compile(node.Operand);
675 throw new NotImplementedException ();
677 // We should be able to ignore Int32ToObject
678 if (node.Method != Runtime.ScriptingRuntimeHelpers.Int32ToObjectMethod) {
679 EmitCall(node.Method);
681 } else if (node.Type == typeof(void)) {
682 CompileAsVoid(node.Operand);
684 Compile(node.Operand);
685 CompileConvertToType(node.Operand.Type, node.Type, node.NodeType == ExpressionType.ConvertChecked);
689 private void CompileConvertToType(Type typeFrom, Type typeTo, bool isChecked) {
690 Debug.Assert(typeFrom != typeof(void) && typeTo != typeof(void));
692 if (TypeUtils.AreEquivalent(typeTo, typeFrom)) {
696 if (TypeUtils.IsNullableType (typeTo)) {
697 typeFrom = TypeUtils.GetNonNullableType (typeFrom);
698 typeTo = TypeUtils.GetNonNullableType (typeTo);
700 var nullValue = _instructions.MakeLabel();
701 var end = _instructions.MakeLabel();
703 _instructions.EmitDup ();
704 _instructions.EmitBranchNull(nullValue);
705 CompileConvertToType (typeFrom, typeTo, isChecked);
706 _instructions.EmitWrap (typeTo);
707 _instructions.EmitBranch (end);
708 _instructions.MarkLabel(nullValue);
709 _instructions.EmitDup (); // Keep null on the stack
710 _instructions.MarkLabel(end);
714 if (TypeUtils.IsNullableType (typeFrom)) {
718 // TODO: should throw same exception as (int)(int?)null
719 throw new NotImplementedException ();
722 TypeCode from = typeFrom.GetTypeCode();
723 TypeCode to = typeTo.GetTypeCode();
724 if (TypeUtils.IsNumeric(from) && TypeUtils.IsNumeric(to)) {
726 _instructions.EmitNumericConvertChecked(from, to);
728 _instructions.EmitNumericConvertUnchecked(from, to);
733 // TODO: Conversions to a super-class or implemented interfaces are no-op.
734 // A conversion to a non-implemented interface or an unrelated class, etc. should fail.
738 private void CompileNegateExpression(UnaryExpression node, bool @checked, bool lifted) {
739 Compile(node.Operand);
740 _instructions.EmitNegate(TypeUtils.GetNonNullableType (node.Type), @checked, lifted);
743 private void CompileNotExpression(UnaryExpression node, bool lifted) {
744 Compile(node.Operand);
745 _instructions.EmitNot(TypeUtils.GetNonNullableType (node.Type), lifted);
748 private void CompileUnaryExpression(Expression expr) {
749 var node = (UnaryExpression)expr;
751 if (node.Method != null) {
752 Compile(node.Operand);
753 EmitCall(node.Method);
755 switch (node.NodeType) {
756 case ExpressionType.ArrayLength:
757 Compile(node.Operand);
758 _instructions.EmitGetArrayLength (node.Type);
760 case ExpressionType.Negate:
761 CompileNegateExpression(node, false, node.IsLifted);
763 case ExpressionType.NegateChecked:
764 CompileNegateExpression(node, true, node.IsLifted);
766 case ExpressionType.Not:
767 CompileNotExpression(node, node.IsLifted);
769 case ExpressionType.UnaryPlus:
770 // unary plus is a nop:
771 Compile(node.Operand);
773 case ExpressionType.TypeAs:
774 CompileTypeAsExpression(node);
777 throw new NotImplementedException(node.NodeType.ToString());
782 private void CompileAndAlsoBinaryExpression(Expression expr) {
783 CompileLogicalBinaryExpression(expr, true);
786 private void CompileOrElseBinaryExpression(Expression expr) {
787 CompileLogicalBinaryExpression(expr, false);
790 private void CompileLogicalBinaryExpression(Expression expr, bool andAlso) {
791 var node = (BinaryExpression)expr;
792 if (node.Method != null) {
793 throw new NotImplementedException();
796 Debug.Assert(node.Left.Type == node.Right.Type);
798 if (node.Left.Type == typeof(bool)) {
799 var elseLabel = _instructions.MakeLabel();
800 var endLabel = _instructions.MakeLabel();
803 _instructions.EmitBranchFalse(elseLabel);
805 _instructions.EmitBranchTrue(elseLabel);
808 _instructions.EmitBranch(endLabel, false, true);
809 _instructions.MarkLabel(elseLabel);
810 _instructions.EmitLoad(!andAlso);
811 _instructions.MarkLabel(endLabel);
815 Debug.Assert(node.Left.Type == typeof(bool?));
816 throw new NotImplementedException();
819 private void CompileConditionalExpression(Expression expr, bool asVoid) {
820 var node = (ConditionalExpression)expr;
823 if (node.IfTrue == AstUtils.Empty()) {
824 var endOfFalse = _instructions.MakeLabel();
825 _instructions.EmitBranchTrue(endOfFalse);
826 Compile(node.IfFalse, asVoid);
827 _instructions.MarkLabel(endOfFalse);
829 var endOfTrue = _instructions.MakeLabel();
830 _instructions.EmitBranchFalse(endOfTrue);
831 Compile(node.IfTrue, asVoid);
833 if (node.IfFalse != AstUtils.Empty()) {
834 var endOfFalse = _instructions.MakeLabel();
835 _instructions.EmitBranch(endOfFalse, false, !asVoid);
836 _instructions.MarkLabel(endOfTrue);
837 Compile(node.IfFalse, asVoid);
838 _instructions.MarkLabel(endOfFalse);
840 _instructions.MarkLabel(endOfTrue);
847 private void CompileLoopExpression(Expression expr) {
848 var node = (LoopExpression)expr;
849 var enterLoop = new EnterLoopInstruction(node, _locals, _compilationThreshold, _instructions.Count);
851 PushLabelBlock(LabelScopeKind.Statement);
852 LabelInfo breakLabel = DefineLabel(node.BreakLabel);
853 LabelInfo continueLabel = DefineLabel(node.ContinueLabel);
855 _instructions.MarkLabel(continueLabel.GetLabel(this));
858 _instructions.Emit(enterLoop);
859 CompileAsVoid(node.Body);
862 _instructions.EmitBranch(continueLabel.GetLabel(this), expr.Type != typeof(void), false);
864 _instructions.MarkLabel(breakLabel.GetLabel(this));
866 PopLabelBlock(LabelScopeKind.Statement);
868 enterLoop.FinishLoop(_instructions.Count);
873 private void CompileSwitchExpression(Expression expr) {
874 var node = (SwitchExpression)expr;
876 // Currently only supports int test values, with no method
877 if (node.SwitchValue.Type != typeof(int) || node.Comparison != null) {
878 throw new NotImplementedException();
881 // Test values must be constant
882 if (!node.Cases.All(c => c.TestValues.All(t => t is ConstantExpression))) {
883 throw new NotImplementedException();
885 LabelInfo end = DefineLabel(null);
886 bool hasValue = node.Type != typeof(void);
888 Compile(node.SwitchValue);
889 var caseDict = new Dictionary<int, int>();
890 int switchIndex = _instructions.Count;
891 _instructions.EmitSwitch(caseDict);
893 if (node.DefaultBody != null) {
894 Compile(node.DefaultBody);
896 Debug.Assert(!hasValue);
898 _instructions.EmitBranch(end.GetLabel(this), false, hasValue);
900 for (int i = 0; i < node.Cases.Count; i++) {
901 var switchCase = node.Cases[i];
903 int caseOffset = _instructions.Count - switchIndex;
904 foreach (ConstantExpression testValue in switchCase.TestValues) {
905 caseDict[(int)testValue.Value] = caseOffset;
908 Compile(switchCase.Body);
910 if (i < node.Cases.Count - 1) {
911 _instructions.EmitBranch(end.GetLabel(this), false, hasValue);
915 _instructions.MarkLabel(end.GetLabel(this));
918 private void CompileLabelExpression(Expression expr) {
919 var node = (LabelExpression)expr;
921 // If we're an immediate child of a block, our label will already
922 // be defined. If not, we need to define our own block so this
923 // label isn't exposed except to its own child expression.
924 LabelInfo label = null;
926 if (_labelBlock.Kind == LabelScopeKind.Block) {
927 _labelBlock.TryGetLabelInfo(node.Target, out label);
929 // We're in a block but didn't find our label, try switch
930 if (label == null && _labelBlock.Parent.Kind == LabelScopeKind.Switch) {
931 _labelBlock.Parent.TryGetLabelInfo(node.Target, out label);
934 // if we're in a switch or block, we should've found the label
935 Debug.Assert(label != null);
939 label = DefineLabel(node.Target);
942 if (node.DefaultValue != null) {
943 if (node.Target.Type == typeof(void)) {
944 CompileAsVoid(node.DefaultValue);
946 Compile(node.DefaultValue);
950 _instructions.MarkLabel(label.GetLabel(this));
953 private void CompileGotoExpression(Expression expr) {
954 var node = (GotoExpression)expr;
955 var labelInfo = ReferenceLabel(node.Target);
957 if (node.Value != null) {
961 _instructions.EmitGoto(labelInfo.GetLabel(this), node.Type != typeof(void), node.Value != null && node.Value.Type != typeof(void));
964 public BranchLabel GetBranchLabel(LabelTarget target) {
965 return ReferenceLabel(target).GetLabel(this);
968 public void PushLabelBlock(LabelScopeKind type) {
969 _labelBlock = new LabelScopeInfo(_labelBlock, type);
972 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "kind")]
973 public void PopLabelBlock(LabelScopeKind kind) {
974 Debug.Assert(_labelBlock != null && _labelBlock.Kind == kind);
975 _labelBlock = _labelBlock.Parent;
978 private LabelInfo EnsureLabel(LabelTarget node) {
980 if (!_treeLabels.TryGetValue(node, out result)) {
981 _treeLabels[node] = result = new LabelInfo(node);
986 private LabelInfo ReferenceLabel(LabelTarget node) {
987 LabelInfo result = EnsureLabel(node);
988 result.Reference(_labelBlock);
992 internal LabelInfo DefineLabel(LabelTarget node) {
994 return new LabelInfo(null);
996 LabelInfo result = EnsureLabel(node);
997 result.Define(_labelBlock);
1001 private bool TryPushLabelBlock(Expression node) {
1002 // Anything that is "statement-like" -- e.g. has no associated
1003 // stack state can be jumped into, with the exception of try-blocks
1004 // We indicate this by a "Block"
1006 // Otherwise, we push an "Expression" to indicate that it can't be
1008 switch (node.NodeType) {
1010 if (_labelBlock.Kind != LabelScopeKind.Expression) {
1011 PushLabelBlock(LabelScopeKind.Expression);
1015 case ExpressionType.Label:
1016 // LabelExpression is a bit special, if it's directly in a
1017 // block it becomes associate with the block's scope. Same
1018 // thing if it's in a switch case body.
1019 if (_labelBlock.Kind == LabelScopeKind.Block) {
1020 var label = ((LabelExpression)node).Target;
1021 if (_labelBlock.ContainsTarget(label)) {
1024 if (_labelBlock.Parent.Kind == LabelScopeKind.Switch &&
1025 _labelBlock.Parent.ContainsTarget(label)) {
1029 PushLabelBlock(LabelScopeKind.Statement);
1031 case ExpressionType.Block:
1032 PushLabelBlock(LabelScopeKind.Block);
1033 // Labels defined immediately in the block are valid for
1035 if (_labelBlock.Parent.Kind != LabelScopeKind.Switch) {
1036 DefineBlockLabels(node);
1039 case ExpressionType.Switch:
1040 PushLabelBlock(LabelScopeKind.Switch);
1041 // Define labels inside of the switch cases so theyare in
1042 // scope for the whole switch. This allows "goto case" and
1043 // "goto default" to be considered as local jumps.
1044 var @switch = (SwitchExpression)node;
1045 foreach (SwitchCase c in @switch.Cases) {
1046 DefineBlockLabels(c.Body);
1048 DefineBlockLabels(@switch.DefaultBody);
1051 // Remove this when Convert(Void) goes away.
1052 case ExpressionType.Convert:
1053 if (node.Type != typeof(void)) {
1054 // treat it as an expression
1057 PushLabelBlock(LabelScopeKind.Statement);
1060 case ExpressionType.Conditional:
1061 case ExpressionType.Loop:
1062 case ExpressionType.Goto:
1063 PushLabelBlock(LabelScopeKind.Statement);
1068 private void DefineBlockLabels(Expression node) {
1069 var block = node as BlockExpression;
1070 if (block == null) {
1074 for (int i = 0, n = block.Expressions.Count; i < n; i++) {
1075 Expression e = block.Expressions[i];
1077 var label = e as LabelExpression;
1078 if (label != null) {
1079 DefineLabel(label.Target);
1084 private HybridReferenceDictionary<LabelTarget, BranchLabel> GetBranchMapping() {
1085 var newLabelMapping = new HybridReferenceDictionary<LabelTarget, BranchLabel>(_treeLabels.Count);
1086 foreach (var kvp in _treeLabels) {
1087 newLabelMapping[kvp.Key] = kvp.Value.GetLabel(this);
1089 return newLabelMapping;
1092 private void CompileThrowUnaryExpression(Expression expr, bool asVoid) {
1093 var node = (UnaryExpression)expr;
1095 if (node.Operand == null) {
1096 CompileParameterExpression(_exceptionForRethrowStack.Peek());
1098 _instructions.EmitRethrowVoid();
1100 _instructions.EmitRethrow();
1103 Compile(node.Operand);
1105 _instructions.EmitThrowVoid();
1107 _instructions.EmitThrow();
1113 // TODO: remove (replace by true fault support)
1114 private bool EndsWithRethrow(Expression expr) {
1115 if (expr.NodeType == ExpressionType.Throw) {
1116 var node = (UnaryExpression)expr;
1117 return node.Operand == null;
1120 BlockExpression block = expr as BlockExpression;
1121 if (block != null) {
1122 return EndsWithRethrow(block.Expressions[block.Expressions.Count - 1]);
1128 // TODO: remove (replace by true fault support)
1129 private void CompileAsVoidRemoveRethrow(Expression expr) {
1130 int stackDepth = _instructions.CurrentStackDepth;
1132 if (expr.NodeType == ExpressionType.Throw) {
1133 Debug.Assert(((UnaryExpression)expr).Operand == null);
1137 var node = (BlockExpression)expr;
1138 var end = CompileBlockStart(node);
1140 CompileAsVoidRemoveRethrow(node.Expressions[node.Expressions.Count - 1]);
1142 Debug.Assert(stackDepth == _instructions.CurrentStackDepth);
1144 CompileBlockEnd(end);
1147 private void CompileTryExpression(Expression expr) {
1148 var node = (TryExpression)expr;
1150 BranchLabel end = _instructions.MakeLabel();
1151 BranchLabel gotoEnd = _instructions.MakeLabel();
1153 int tryStart = _instructions.Count;
1155 BranchLabel startOfFinally = null;
1156 if (node.Finally != null) {
1157 startOfFinally = _instructions.MakeLabel();
1158 _instructions.EmitEnterTryFinally(startOfFinally);
1161 PushLabelBlock(LabelScopeKind.Try);
1164 bool hasValue = node.Body.Type != typeof(void);
1165 int tryEnd = _instructions.Count;
1167 // handlers jump here:
1168 _instructions.MarkLabel(gotoEnd);
1169 _instructions.EmitGoto(end, hasValue, hasValue);
1171 // keep the result on the stack:
1172 if (node.Handlers.Count > 0) {
1173 // TODO: emulates faults (replace by true fault support)
1174 if (node.Finally == null && node.Handlers.Count == 1) {
1175 var handler = node.Handlers[0];
1176 if (handler.Filter == null && handler.Test == typeof(Exception) && handler.Variable == null) {
1177 if (EndsWithRethrow(handler.Body)) {
1179 _instructions.EmitEnterExceptionHandlerNonVoid();
1181 _instructions.EmitEnterExceptionHandlerVoid();
1184 // at this point the stack balance is prepared for the hidden exception variable:
1185 int handlerLabel = _instructions.MarkRuntimeLabel();
1186 int handlerStart = _instructions.Count;
1188 CompileAsVoidRemoveRethrow(handler.Body);
1189 _instructions.EmitLeaveFault(hasValue);
1190 _instructions.MarkLabel(end);
1192 _handlers.Add(new ExceptionHandler(tryStart, tryEnd, handlerLabel, handlerStart, null));
1193 PopLabelBlock(LabelScopeKind.Try);
1199 foreach (var handler in node.Handlers) {
1200 PushLabelBlock(LabelScopeKind.Catch);
1202 if (handler.Filter != null) {
1203 //PushLabelBlock(LabelScopeKind.Filter);
1204 throw new NotImplementedException();
1205 //PopLabelBlock(LabelScopeKind.Filter);
1208 var parameter = handler.Variable ?? Expression.Parameter(handler.Test);
1210 var local = _locals.DefineLocal(parameter, _instructions.Count);
1211 _exceptionForRethrowStack.Push(parameter);
1213 // add a stack balancing nop instruction (exception handling pushes the current exception):
1215 _instructions.EmitEnterExceptionHandlerNonVoid();
1217 _instructions.EmitEnterExceptionHandlerVoid();
1220 // at this point the stack balance is prepared for the hidden exception variable:
1221 int handlerLabel = _instructions.MarkRuntimeLabel();
1222 int handlerStart = _instructions.Count;
1224 CompileSetVariable(parameter, true);
1225 Compile(handler.Body);
1227 _exceptionForRethrowStack.Pop();
1229 // keep the value of the body on the stack:
1230 Debug.Assert(hasValue == (handler.Body.Type != typeof(void)));
1231 _instructions.EmitLeaveExceptionHandler(hasValue, gotoEnd);
1233 _handlers.Add(new ExceptionHandler(tryStart, tryEnd, handlerLabel, handlerStart, handler.Test));
1235 PopLabelBlock(LabelScopeKind.Catch);
1237 _locals.UndefineLocal(local, _instructions.Count);
1240 if (node.Fault != null) {
1241 throw new NotImplementedException();
1245 if (node.Finally != null) {
1246 PushLabelBlock(LabelScopeKind.Finally);
1248 _instructions.MarkLabel(startOfFinally);
1249 _instructions.EmitEnterFinally();
1250 CompileAsVoid(node.Finally);
1251 _instructions.EmitLeaveFinally();
1253 PopLabelBlock(LabelScopeKind.Finally);
1256 _instructions.MarkLabel(end);
1258 PopLabelBlock(LabelScopeKind.Try);
1261 private void CompileDynamicExpression(Expression expr) {
1262 var node = (DynamicExpression)expr;
1264 foreach (var arg in node.Arguments) {
1268 _instructions.EmitDynamic(node.DelegateType, node.Binder);
1271 private void CompileMethodCallExpression(Expression expr) {
1272 var node = (MethodCallExpression)expr;
1274 var parameters = node.Method.GetParameters();
1277 // Support pass by reference.
1278 // Note that LoopCompiler needs to be updated too.
1280 // force compilation for now for ref types
1281 // also could be a mutable value type, Delegate.CreateDelegate and MethodInfo.Invoke both can't handle this, we
1282 // need to generate code.
1283 if (!CollectionUtils.TrueForAll(parameters, (p) => !p.ParameterType.IsByRef) ||
1284 (!node.Method.IsStatic && node.Method.DeclaringType.IsValueType() && !node.Method.DeclaringType.IsPrimitive())) {
1285 #if MONO_INTERPRETER
1286 throw new NotImplementedException ("Interpreter of ref types");
1288 _forceCompile = true;
1292 // CF bug workaround
1293 // TODO: can we do better if the delegate targets LightLambda.Run* method?
1294 if (PlatformAdaptationLayer.IsCompactFramework &&
1295 node.Method.Name == "Invoke" && typeof(Delegate).IsAssignableFrom(node.Object.Type) && !node.Method.IsStatic) {
1301 node.Object.Type.GetMethod("DynamicInvoke"),
1302 Expression.NewArrayInit(typeof(object), node.Arguments.Map((e) => AstUtils.Convert(e, typeof(object))))
1309 if (!node.Method.IsStatic) {
1310 Compile(node.Object);
1313 foreach (var arg in node.Arguments) {
1317 EmitCall(node.Method, parameters);
1321 public void EmitCall(MethodInfo method) {
1322 EmitCall(method, method.GetParameters());
1325 public void EmitCall(MethodInfo method, ParameterInfo[] parameters) {
1326 Instruction instruction;
1329 instruction = CallInstruction.Create(method, parameters);
1330 } catch (SecurityException) {
1331 _forceCompile = true;
1333 _instructions.Emit(new PopNInstruction((method.IsStatic ? 0 : 1) + parameters.Length));
1334 if (method.ReturnType != typeof(void)) {
1335 _instructions.EmitLoad(null);
1341 _instructions.Emit(instruction);
1344 private void CompileNewExpression(Expression expr) {
1345 var node = (NewExpression)expr;
1347 if (node.Constructor != null) {
1348 var parameters = node.Constructor.GetParameters();
1349 if (!CollectionUtils.TrueForAll(parameters, (p) => !p.ParameterType.IsByRef)
1351 || node.Constructor.DeclaringType == typeof(DynamicMethod)
1354 _forceCompile = true;
1358 if (node.Constructor != null) {
1359 foreach (var arg in node.Arguments) {
1362 _instructions.EmitNew(node.Constructor);
1364 Debug.Assert(expr.Type.IsValueType());
1365 _instructions.EmitDefaultValue(node.Type);
1369 private void CompileMemberExpression(Expression expr) {
1370 var node = (MemberExpression)expr;
1372 var member = node.Member;
1373 FieldInfo fi = member as FieldInfo;
1376 _instructions.EmitLoad(fi.GetRawConstantValue(), fi.FieldType);
1377 } else if (fi.IsStatic) {
1378 if (fi.IsInitOnly) {
1379 _instructions.EmitLoad(fi.GetValue(null), fi.FieldType);
1381 _instructions.EmitLoadField(fi);
1384 Compile(node.Expression);
1385 _instructions.EmitLoadField(fi);
1390 PropertyInfo pi = member as PropertyInfo;
1392 var method = pi.GetGetMethod(true);
1393 if (node.Expression != null) {
1394 Compile(node.Expression);
1401 throw new System.NotImplementedException();
1404 private void CompileNewArrayExpression(Expression expr) {
1405 var node = (NewArrayExpression)expr;
1407 foreach (var arg in node.Expressions) {
1411 Type elementType = node.Type.GetElementType();
1412 int rank = node.Expressions.Count;
1414 if (node.NodeType == ExpressionType.NewArrayInit) {
1415 _instructions.EmitNewArrayInit(elementType, rank);
1416 } else if (node.NodeType == ExpressionType.NewArrayBounds) {
1418 _instructions.EmitNewArray(elementType);
1420 _instructions.EmitNewArrayBounds(elementType, rank);
1423 throw new System.NotImplementedException();
1427 private void CompileExtensionExpression(Expression expr) {
1428 var instructionProvider = expr as IInstructionProvider;
1429 if (instructionProvider != null) {
1430 instructionProvider.AddInstructions(this);
1434 if (expr.CanReduce) {
1435 Compile(expr.Reduce());
1437 throw new System.NotImplementedException();
1442 private void CompileDebugInfoExpression(Expression expr) {
1443 var node = (DebugInfoExpression)expr;
1444 int start = _instructions.Count;
1445 var info = new DebugInfo()
1448 FileName = node.Document.FileName,
1449 StartLine = node.StartLine,
1450 EndLine = node.EndLine,
1451 IsClear = node.IsClear
1453 _debugInfos.Add(info);
1456 private void CompileRuntimeVariablesExpression(Expression expr) {
1457 // Generates IRuntimeVariables for all requested variables
1458 var node = (RuntimeVariablesExpression)expr;
1459 foreach (var variable in node.Variables) {
1460 EnsureAvailableForClosure(variable);
1461 CompileGetBoxedVariable(variable);
1464 _instructions.EmitNewRuntimeVariables(node.Variables.Count);
1468 private void CompileLambdaExpression(Expression expr) {
1469 var node = (LambdaExpression)expr;
1470 var compiler = new LightCompiler(this);
1471 var creator = compiler.CompileTop(node);
1473 if (compiler._locals.ClosureVariables != null) {
1474 foreach (ParameterExpression variable in compiler._locals.ClosureVariables.Keys) {
1475 CompileGetBoxedVariable(variable);
1478 _instructions.EmitCreateDelegate(creator);
1481 private void CompileCoalesceBinaryExpression(Expression expr) {
1482 var node = (BinaryExpression)expr;
1484 if (TypeUtils.IsNullableType(node.Left.Type)) {
1485 throw new NotImplementedException();
1486 } else if (node.Conversion != null) {
1487 throw new NotImplementedException();
1489 var leftNotNull = _instructions.MakeLabel();
1491 _instructions.EmitCoalescingBranch(leftNotNull);
1492 _instructions.EmitPop();
1493 Compile(node.Right);
1494 _instructions.MarkLabel(leftNotNull);
1498 private void CompileInvocationExpression(Expression expr) {
1499 var node = (InvocationExpression)expr;
1501 // TODO: LambdaOperand optimization (see compiler)
1502 if (typeof(LambdaExpression).IsAssignableFrom(node.Expression.Type)) {
1503 throw new System.NotImplementedException();
1506 // TODO: do not create a new Call Expression
1507 if (PlatformAdaptationLayer.IsCompactFramework) {
1508 // Workaround for a bug in Compact Framework
1513 node.Expression.Type.GetMethod("DynamicInvoke"),
1514 Expression.NewArrayInit(typeof(object), node.Arguments.Map((e) => AstUtils.Convert(e, typeof(object))))
1520 CompileMethodCallExpression(Expression.Call(node.Expression, node.Expression.Type.GetMethod("Invoke"), node.Arguments));
1524 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "expr")]
1525 private void CompileListInitExpression(Expression expr) {
1526 throw new System.NotImplementedException();
1529 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "expr")]
1530 private void CompileMemberInitExpression(Expression expr) {
1531 throw new System.NotImplementedException();
1534 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "expr")]
1535 private void CompileQuoteUnaryExpression(Expression expr) {
1536 throw new System.NotImplementedException();
1539 private void CompileUnboxUnaryExpression(Expression expr) {
1540 var node = (UnaryExpression)expr;
1541 // unboxing is a nop:
1542 Compile(node.Operand);
1545 private void CompileTypeEqualExpression(Expression expr) {
1546 Debug.Assert(expr.NodeType == ExpressionType.TypeEqual);
1547 var node = (TypeBinaryExpression)expr;
1549 Compile(node.Expression);
1550 _instructions.EmitLoad(node.TypeOperand);
1551 _instructions.EmitTypeEquals();
1554 private void CompileTypeAsExpression(UnaryExpression node) {
1555 Compile(node.Operand);
1556 _instructions.EmitTypeAs(node.Type);
1559 private void CompileTypeIsExpression(Expression expr) {
1560 Debug.Assert(expr.NodeType == ExpressionType.TypeIs);
1561 var node = (TypeBinaryExpression)expr;
1563 Compile(node.Expression);
1564 if (node.Expression.Type == typeof (void)) {
1565 _instructions.Emit (InstructionFactory<bool>.Factory.DefaultValue ());
1569 // use TypeEqual for sealed types:
1570 if (node.TypeOperand.IsSealed()) {
1571 _instructions.EmitLoad(node.TypeOperand);
1572 _instructions.EmitTypeEquals();
1574 _instructions.EmitTypeIs(node.TypeOperand);
1578 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "expr")]
1579 private void CompileReducibleExpression(Expression expr) {
1580 throw new System.NotImplementedException();
1583 internal void Compile(Expression expr, bool asVoid) {
1585 CompileAsVoid(expr);
1591 internal void CompileAsVoid(Expression expr) {
1592 bool pushLabelBlock = TryPushLabelBlock(expr);
1593 int startingStackDepth = _instructions.CurrentStackDepth;
1594 switch (expr.NodeType) {
1595 case ExpressionType.Assign:
1596 CompileAssignBinaryExpression(expr, true);
1599 case ExpressionType.Block:
1600 CompileBlockExpression(expr, true);
1603 case ExpressionType.Throw:
1604 CompileThrowUnaryExpression(expr, true);
1607 case ExpressionType.Constant:
1608 case ExpressionType.Default:
1609 case ExpressionType.Parameter:
1614 CompileNoLabelPush(expr);
1615 if (expr.Type != typeof(void)) {
1616 _instructions.EmitPop();
1620 Debug.Assert(_instructions.CurrentStackDepth == startingStackDepth);
1621 if (pushLabelBlock) {
1622 PopLabelBlock(_labelBlock.Kind);
1626 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
1627 private void CompileNoLabelPush(Expression expr) {
1628 int startingStackDepth = _instructions.CurrentStackDepth;
1629 switch (expr.NodeType) {
1630 case ExpressionType.Add: CompileBinaryExpression(expr); break;
1631 case ExpressionType.AddChecked: CompileBinaryExpression(expr); break;
1632 case ExpressionType.And: CompileBinaryExpression(expr); break;
1633 case ExpressionType.AndAlso: CompileAndAlsoBinaryExpression(expr); break;
1634 case ExpressionType.ArrayLength: CompileUnaryExpression(expr); break;
1635 case ExpressionType.ArrayIndex: CompileBinaryExpression(expr); break;
1636 case ExpressionType.Call: CompileMethodCallExpression(expr); break;
1637 case ExpressionType.Coalesce: CompileCoalesceBinaryExpression(expr); break;
1638 case ExpressionType.Conditional: CompileConditionalExpression(expr, expr.Type == typeof(void)); break;
1639 case ExpressionType.Constant: CompileConstantExpression(expr); break;
1640 case ExpressionType.Convert: CompileConvertUnaryExpression(expr); break;
1641 case ExpressionType.ConvertChecked: CompileConvertUnaryExpression(expr); break;
1642 case ExpressionType.Divide: CompileBinaryExpression(expr); break;
1643 case ExpressionType.Equal: CompileBinaryExpression(expr); break;
1644 case ExpressionType.ExclusiveOr: CompileBinaryExpression(expr); break;
1645 case ExpressionType.GreaterThan: CompileBinaryExpression(expr); break;
1646 case ExpressionType.GreaterThanOrEqual: CompileBinaryExpression(expr); break;
1647 case ExpressionType.Invoke: CompileInvocationExpression(expr); break;
1648 case ExpressionType.Lambda: CompileLambdaExpression(expr); break;
1649 case ExpressionType.LeftShift: CompileBinaryExpression(expr); break;
1650 case ExpressionType.LessThan: CompileBinaryExpression(expr); break;
1651 case ExpressionType.LessThanOrEqual: CompileBinaryExpression(expr); break;
1652 case ExpressionType.ListInit: CompileListInitExpression(expr); break;
1653 case ExpressionType.MemberAccess: CompileMemberExpression(expr); break;
1654 case ExpressionType.MemberInit: CompileMemberInitExpression(expr); break;
1655 case ExpressionType.Modulo: CompileBinaryExpression(expr); break;
1656 case ExpressionType.Multiply: CompileBinaryExpression(expr); break;
1657 case ExpressionType.MultiplyChecked: CompileBinaryExpression(expr); break;
1658 case ExpressionType.Negate: CompileUnaryExpression(expr); break;
1659 case ExpressionType.UnaryPlus: CompileUnaryExpression(expr); break;
1660 case ExpressionType.NegateChecked: CompileUnaryExpression(expr); break;
1661 case ExpressionType.New: CompileNewExpression(expr); break;
1662 case ExpressionType.NewArrayInit: CompileNewArrayExpression(expr); break;
1663 case ExpressionType.NewArrayBounds: CompileNewArrayExpression(expr); break;
1664 case ExpressionType.Not: CompileUnaryExpression(expr); break;
1665 case ExpressionType.NotEqual: CompileBinaryExpression(expr); break;
1666 case ExpressionType.Or: CompileBinaryExpression(expr); break;
1667 case ExpressionType.OrElse: CompileOrElseBinaryExpression(expr); break;
1668 case ExpressionType.Parameter: CompileParameterExpression(expr); break;
1669 case ExpressionType.Power: CompileBinaryExpression(expr); break;
1670 case ExpressionType.Quote: CompileQuoteUnaryExpression(expr); break;
1671 case ExpressionType.RightShift: CompileBinaryExpression(expr); break;
1672 case ExpressionType.Subtract: CompileBinaryExpression(expr); break;
1673 case ExpressionType.SubtractChecked: CompileBinaryExpression(expr); break;
1674 case ExpressionType.TypeAs: CompileUnaryExpression(expr); break;
1675 case ExpressionType.TypeIs: CompileTypeIsExpression(expr); break;
1676 case ExpressionType.Assign: CompileAssignBinaryExpression(expr, expr.Type == typeof(void)); break;
1677 case ExpressionType.Block: CompileBlockExpression(expr, expr.Type == typeof(void)); break;
1678 case ExpressionType.DebugInfo: CompileDebugInfoExpression(expr); break;
1679 case ExpressionType.Decrement: CompileUnaryExpression(expr); break;
1680 case ExpressionType.Dynamic: CompileDynamicExpression(expr); break;
1681 case ExpressionType.Default: CompileDefaultExpression(expr); break;
1682 case ExpressionType.Extension: CompileExtensionExpression(expr); break;
1683 case ExpressionType.Goto: CompileGotoExpression(expr); break;
1684 case ExpressionType.Increment: CompileUnaryExpression(expr); break;
1685 case ExpressionType.Index: CompileIndexExpression(expr); break;
1686 case ExpressionType.Label: CompileLabelExpression(expr); break;
1687 case ExpressionType.RuntimeVariables: CompileRuntimeVariablesExpression(expr); break;
1688 case ExpressionType.Loop: CompileLoopExpression(expr); break;
1689 case ExpressionType.Switch: CompileSwitchExpression(expr); break;
1690 case ExpressionType.Throw: CompileThrowUnaryExpression(expr, expr.Type == typeof(void)); break;
1691 case ExpressionType.Try: CompileTryExpression(expr); break;
1692 case ExpressionType.Unbox: CompileUnboxUnaryExpression(expr); break;
1693 case ExpressionType.TypeEqual: CompileTypeEqualExpression(expr); break;
1694 case ExpressionType.OnesComplement: CompileUnaryExpression(expr); break;
1695 case ExpressionType.IsTrue: CompileUnaryExpression(expr); break;
1696 case ExpressionType.IsFalse: CompileUnaryExpression(expr); break;
1697 case ExpressionType.AddAssign:
1698 case ExpressionType.AndAssign:
1699 case ExpressionType.DivideAssign:
1700 case ExpressionType.ExclusiveOrAssign:
1701 case ExpressionType.LeftShiftAssign:
1702 case ExpressionType.ModuloAssign:
1703 case ExpressionType.MultiplyAssign:
1704 case ExpressionType.OrAssign:
1705 case ExpressionType.PowerAssign:
1706 case ExpressionType.RightShiftAssign:
1707 case ExpressionType.SubtractAssign:
1708 case ExpressionType.AddAssignChecked:
1709 case ExpressionType.MultiplyAssignChecked:
1710 case ExpressionType.SubtractAssignChecked:
1711 case ExpressionType.PreIncrementAssign:
1712 case ExpressionType.PreDecrementAssign:
1713 case ExpressionType.PostIncrementAssign:
1714 case ExpressionType.PostDecrementAssign:
1715 CompileReducibleExpression(expr); break;
1716 default: throw Assert.Unreachable;
1718 Debug.Assert(_instructions.CurrentStackDepth == startingStackDepth + (expr.Type == typeof(void) ? 0 : 1));
1721 public void Compile(Expression expr) {
1722 bool pushLabelBlock = TryPushLabelBlock(expr);
1723 CompileNoLabelPush(expr);
1724 if (pushLabelBlock) {
1725 PopLabelBlock(_labelBlock.Kind);