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.Diagnostics;
18 using System.Dynamic.Utils;
19 using System.Reflection;
20 using System.Reflection.Emit;
23 namespace Microsoft.Scripting.Ast.Compiler {
25 namespace System.Linq.Expressions.Compiler {
28 partial class LambdaCompiler {
32 private void EmitConditionalExpression(Expression expr, CompilationFlags flags) {
33 ConditionalExpression node = (ConditionalExpression)expr;
34 Debug.Assert(node.Test.Type == typeof(bool));
35 Label labFalse = _ilg.DefineLabel();
36 EmitExpressionAndBranch(false, node.Test, labFalse);
37 EmitExpressionAsType(node.IfTrue, node.Type, flags);
39 if (NotEmpty(node.IfFalse)) {
40 Label labEnd = _ilg.DefineLabel();
41 if ((flags & CompilationFlags.EmitAsTailCallMask) == CompilationFlags.EmitAsTail) {
42 // We know the conditional expression is at the end of the lambda,
43 // so it is safe to emit Ret here.
44 _ilg.Emit(OpCodes.Ret);
46 _ilg.Emit(OpCodes.Br, labEnd);
48 _ilg.MarkLabel(labFalse);
49 EmitExpressionAsType(node.IfFalse, node.Type, flags);
50 _ilg.MarkLabel(labEnd);
52 _ilg.MarkLabel(labFalse);
57 /// returns true if the expression is not empty, otherwise false.
59 private static bool NotEmpty(Expression node) {
60 var empty = node as DefaultExpression;
61 if (empty == null || empty.Type != typeof(void)) {
69 /// returns true if the expression is NOT empty and is not debug info,
70 /// or a block that contains only insignificant expressions.
72 private static bool Significant(Expression node) {
73 var block = node as BlockExpression;
75 for (int i = 0; i < block.ExpressionCount; i++) {
76 if (Significant(block.GetExpression(i))) {
82 return NotEmpty(node) && !(node is DebugInfoExpression);
90 private void EmitCoalesceBinaryExpression(Expression expr) {
91 BinaryExpression b = (BinaryExpression)expr;
92 Debug.Assert(b.Method == null);
94 if (TypeUtils.IsNullableType(b.Left.Type)) {
95 EmitNullableCoalesce(b);
96 } else if (b.Left.Type.IsValueType) {
97 throw Error.CoalesceUsedOnNonNullType();
98 } else if (b.Conversion != null) {
99 EmitLambdaReferenceCoalesce(b);
101 EmitReferenceCoalesceWithoutConversion(b);
106 private void EmitNullableCoalesce(BinaryExpression b) {
107 Debug.Assert(b.Method == null);
109 LocalBuilder loc = GetLocal(b.Left.Type);
110 Label labIfNull = _ilg.DefineLabel();
111 Label labEnd = _ilg.DefineLabel();
112 EmitExpression(b.Left);
113 _ilg.Emit(OpCodes.Stloc, loc);
114 _ilg.Emit(OpCodes.Ldloca, loc);
115 _ilg.EmitHasValue(b.Left.Type);
116 _ilg.Emit(OpCodes.Brfalse, labIfNull);
118 Type nnLeftType = TypeUtils.GetNonNullableType(b.Left.Type);
119 if (b.Conversion != null) {
120 Debug.Assert(b.Conversion.Parameters.Count == 1);
121 ParameterExpression p = b.Conversion.Parameters[0];
122 Debug.Assert(p.Type.IsAssignableFrom(b.Left.Type) ||
123 p.Type.IsAssignableFrom(nnLeftType));
125 // emit the delegate instance
126 EmitLambdaExpression(b.Conversion);
129 if (!p.Type.IsAssignableFrom(b.Left.Type)) {
130 _ilg.Emit(OpCodes.Ldloca, loc);
131 _ilg.EmitGetValueOrDefault(b.Left.Type);
133 _ilg.Emit(OpCodes.Ldloc, loc);
136 // emit call to invoke
137 _ilg.Emit(OpCodes.Callvirt, b.Conversion.Type.GetMethod("Invoke"));
138 } else if (!TypeUtils.AreEquivalent(b.Type, nnLeftType)) {
139 _ilg.Emit(OpCodes.Ldloca, loc);
140 _ilg.EmitGetValueOrDefault(b.Left.Type);
141 _ilg.EmitConvertToType(nnLeftType, b.Type, true);
143 _ilg.Emit(OpCodes.Ldloca, loc);
144 _ilg.EmitGetValueOrDefault(b.Left.Type);
148 _ilg.Emit(OpCodes.Br, labEnd);
149 _ilg.MarkLabel(labIfNull);
150 EmitExpression(b.Right);
151 if (!TypeUtils.AreEquivalent(b.Right.Type, b.Type)) {
152 _ilg.EmitConvertToType(b.Right.Type, b.Type, true);
154 _ilg.MarkLabel(labEnd);
158 private void EmitLambdaReferenceCoalesce(BinaryExpression b) {
159 LocalBuilder loc = GetLocal(b.Left.Type);
160 Label labEnd = _ilg.DefineLabel();
161 Label labNotNull = _ilg.DefineLabel();
162 EmitExpression(b.Left);
163 _ilg.Emit(OpCodes.Dup);
164 _ilg.Emit(OpCodes.Stloc, loc);
165 _ilg.Emit(OpCodes.Ldnull);
166 _ilg.Emit(OpCodes.Ceq);
167 _ilg.Emit(OpCodes.Brfalse, labNotNull);
168 EmitExpression(b.Right);
169 _ilg.Emit(OpCodes.Br, labEnd);
171 // if not null, call conversion
172 _ilg.MarkLabel(labNotNull);
173 Debug.Assert(b.Conversion.Parameters.Count == 1);
175 // emit the delegate instance
176 EmitLambdaExpression(b.Conversion);
179 _ilg.Emit(OpCodes.Ldloc, loc);
182 // emit call to invoke
183 _ilg.Emit(OpCodes.Callvirt, b.Conversion.Type.GetMethod("Invoke"));
185 _ilg.MarkLabel(labEnd);
189 private void EmitReferenceCoalesceWithoutConversion(BinaryExpression b) {
190 Label labEnd = _ilg.DefineLabel();
191 Label labCast = _ilg.DefineLabel();
192 EmitExpression(b.Left);
193 _ilg.Emit(OpCodes.Dup);
194 _ilg.Emit(OpCodes.Ldnull);
195 _ilg.Emit(OpCodes.Ceq);
196 _ilg.Emit(OpCodes.Brfalse, labCast);
197 _ilg.Emit(OpCodes.Pop);
198 EmitExpression(b.Right);
199 if (!TypeUtils.AreEquivalent(b.Right.Type, b.Type)) {
200 if (b.Right.Type.IsValueType) {
201 _ilg.Emit(OpCodes.Box, b.Right.Type);
203 _ilg.Emit(OpCodes.Castclass, b.Type);
205 _ilg.Emit(OpCodes.Br_S, labEnd);
206 _ilg.MarkLabel(labCast);
207 if (!TypeUtils.AreEquivalent(b.Left.Type, b.Type)) {
208 Debug.Assert(!b.Left.Type.IsValueType);
209 _ilg.Emit(OpCodes.Castclass, b.Type);
211 _ilg.MarkLabel(labEnd);
218 private void EmitLiftedAndAlso(BinaryExpression b) {
219 Type type = typeof(bool?);
220 Label labComputeRight = _ilg.DefineLabel();
221 Label labReturnFalse = _ilg.DefineLabel();
222 Label labReturnNull = _ilg.DefineLabel();
223 Label labReturnValue = _ilg.DefineLabel();
224 Label labExit = _ilg.DefineLabel();
225 LocalBuilder locLeft = GetLocal(type);
226 LocalBuilder locRight = GetLocal(type);
227 EmitExpression(b.Left);
228 _ilg.Emit(OpCodes.Stloc, locLeft);
229 _ilg.Emit(OpCodes.Ldloca, locLeft);
230 _ilg.EmitHasValue(type);
231 _ilg.Emit(OpCodes.Brfalse, labComputeRight);
232 _ilg.Emit(OpCodes.Ldloca, locLeft);
233 _ilg.EmitGetValueOrDefault(type);
234 _ilg.Emit(OpCodes.Ldc_I4_0);
235 _ilg.Emit(OpCodes.Ceq);
236 _ilg.Emit(OpCodes.Brtrue, labReturnFalse);
238 _ilg.MarkLabel(labComputeRight);
239 EmitExpression(b.Right);
240 _ilg.Emit(OpCodes.Stloc, locRight);
241 _ilg.Emit(OpCodes.Ldloca, locRight);
242 _ilg.EmitHasValue(type);
243 _ilg.Emit(OpCodes.Brfalse_S, labReturnNull);
244 _ilg.Emit(OpCodes.Ldloca, locRight);
245 _ilg.EmitGetValueOrDefault(type);
246 _ilg.Emit(OpCodes.Ldc_I4_0);
247 _ilg.Emit(OpCodes.Ceq);
248 _ilg.Emit(OpCodes.Brtrue_S, labReturnFalse);
249 // check left for null again
250 _ilg.Emit(OpCodes.Ldloca, locLeft);
251 _ilg.EmitHasValue(type);
252 _ilg.Emit(OpCodes.Brfalse, labReturnNull);
254 _ilg.Emit(OpCodes.Ldc_I4_1);
255 _ilg.Emit(OpCodes.Br_S, labReturnValue);
257 _ilg.MarkLabel(labReturnFalse);
258 _ilg.Emit(OpCodes.Ldc_I4_0);
259 _ilg.Emit(OpCodes.Br_S, labReturnValue);
260 _ilg.MarkLabel(labReturnValue);
261 ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) });
262 _ilg.Emit(OpCodes.Newobj, ci);
263 _ilg.Emit(OpCodes.Stloc, locLeft);
264 _ilg.Emit(OpCodes.Br, labExit);
266 _ilg.MarkLabel(labReturnNull);
267 _ilg.Emit(OpCodes.Ldloca, locLeft);
268 _ilg.Emit(OpCodes.Initobj, type);
269 _ilg.MarkLabel(labExit);
270 _ilg.Emit(OpCodes.Ldloc, locLeft);
275 private void EmitMethodAndAlso(BinaryExpression b, CompilationFlags flags) {
276 Label labEnd = _ilg.DefineLabel();
277 EmitExpression(b.Left);
278 _ilg.Emit(OpCodes.Dup);
279 MethodInfo opFalse = TypeUtils.GetBooleanOperator(b.Method.DeclaringType, "op_False");
280 Debug.Assert(opFalse != null, "factory should check that the method exists");
281 _ilg.Emit(OpCodes.Call, opFalse);
282 _ilg.Emit(OpCodes.Brtrue, labEnd);
284 //store the value of the left value before emitting b.Right to empty the evaluation stack
285 LocalBuilder locLeft = GetLocal(b.Left.Type);
286 _ilg.Emit(OpCodes.Stloc, locLeft);
288 EmitExpression(b.Right);
289 //store the right value to local
290 LocalBuilder locRight = GetLocal(b.Right.Type);
291 _ilg.Emit(OpCodes.Stloc, locRight);
293 Debug.Assert(b.Method.IsStatic);
294 _ilg.Emit(OpCodes.Ldloc, locLeft);
295 _ilg.Emit(OpCodes.Ldloc, locRight);
296 if ((flags & CompilationFlags.EmitAsTailCallMask) == CompilationFlags.EmitAsTail) {
297 _ilg.Emit(OpCodes.Tailcall);
299 _ilg.Emit(OpCodes.Call, b.Method);
302 _ilg.MarkLabel(labEnd);
305 private void EmitUnliftedAndAlso(BinaryExpression b) {
306 Label @else = _ilg.DefineLabel();
307 Label end = _ilg.DefineLabel();
308 EmitExpressionAndBranch(false, b.Left, @else);
309 EmitExpression(b.Right);
310 _ilg.Emit(OpCodes.Br, end);
311 _ilg.MarkLabel(@else);
312 _ilg.Emit(OpCodes.Ldc_I4_0);
316 private void EmitAndAlsoBinaryExpression(Expression expr, CompilationFlags flags) {
317 BinaryExpression b = (BinaryExpression)expr;
319 if (b.Method != null && !b.IsLiftedLogical) {
320 EmitMethodAndAlso(b, flags);
321 } else if (b.Left.Type == typeof(bool?)) {
322 EmitLiftedAndAlso(b);
323 } else if (b.IsLiftedLogical) {
324 EmitExpression(b.ReduceUserdefinedLifted());
326 EmitUnliftedAndAlso(b);
334 private void EmitLiftedOrElse(BinaryExpression b) {
335 Type type = typeof(bool?);
336 Label labComputeRight = _ilg.DefineLabel();
337 Label labReturnTrue = _ilg.DefineLabel();
338 Label labReturnNull = _ilg.DefineLabel();
339 Label labReturnValue = _ilg.DefineLabel();
340 Label labExit = _ilg.DefineLabel();
341 LocalBuilder locLeft = GetLocal(type);
342 LocalBuilder locRight = GetLocal(type);
343 EmitExpression(b.Left);
344 _ilg.Emit(OpCodes.Stloc, locLeft);
345 _ilg.Emit(OpCodes.Ldloca, locLeft);
346 _ilg.EmitHasValue(type);
347 _ilg.Emit(OpCodes.Brfalse, labComputeRight);
348 _ilg.Emit(OpCodes.Ldloca, locLeft);
349 _ilg.EmitGetValueOrDefault(type);
350 _ilg.Emit(OpCodes.Ldc_I4_0);
351 _ilg.Emit(OpCodes.Ceq);
352 _ilg.Emit(OpCodes.Brfalse, labReturnTrue);
354 _ilg.MarkLabel(labComputeRight);
355 EmitExpression(b.Right);
356 _ilg.Emit(OpCodes.Stloc, locRight);
357 _ilg.Emit(OpCodes.Ldloca, locRight);
358 _ilg.EmitHasValue(type);
359 _ilg.Emit(OpCodes.Brfalse_S, labReturnNull);
360 _ilg.Emit(OpCodes.Ldloca, locRight);
361 _ilg.EmitGetValueOrDefault(type);
362 _ilg.Emit(OpCodes.Ldc_I4_0);
363 _ilg.Emit(OpCodes.Ceq);
364 _ilg.Emit(OpCodes.Brfalse_S, labReturnTrue);
365 // check left for null again
366 _ilg.Emit(OpCodes.Ldloca, locLeft);
367 _ilg.EmitHasValue(type);
368 _ilg.Emit(OpCodes.Brfalse, labReturnNull);
370 _ilg.Emit(OpCodes.Ldc_I4_0);
371 _ilg.Emit(OpCodes.Br_S, labReturnValue);
373 _ilg.MarkLabel(labReturnTrue);
374 _ilg.Emit(OpCodes.Ldc_I4_1);
375 _ilg.Emit(OpCodes.Br_S, labReturnValue);
376 _ilg.MarkLabel(labReturnValue);
377 ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) });
378 _ilg.Emit(OpCodes.Newobj, ci);
379 _ilg.Emit(OpCodes.Stloc, locLeft);
380 _ilg.Emit(OpCodes.Br, labExit);
382 _ilg.MarkLabel(labReturnNull);
383 _ilg.Emit(OpCodes.Ldloca, locLeft);
384 _ilg.Emit(OpCodes.Initobj, type);
385 _ilg.MarkLabel(labExit);
386 _ilg.Emit(OpCodes.Ldloc, locLeft);
391 private void EmitUnliftedOrElse(BinaryExpression b) {
392 Label @else = _ilg.DefineLabel();
393 Label end = _ilg.DefineLabel();
394 EmitExpressionAndBranch(false, b.Left, @else);
395 _ilg.Emit(OpCodes.Ldc_I4_1);
396 _ilg.Emit(OpCodes.Br, end);
397 _ilg.MarkLabel(@else);
398 EmitExpression(b.Right);
402 private void EmitMethodOrElse(BinaryExpression b, CompilationFlags flags) {
403 Label labEnd = _ilg.DefineLabel();
404 EmitExpression(b.Left);
405 _ilg.Emit(OpCodes.Dup);
406 MethodInfo opTrue = TypeUtils.GetBooleanOperator(b.Method.DeclaringType, "op_True");
407 Debug.Assert(opTrue != null, "factory should check that the method exists");
408 _ilg.Emit(OpCodes.Call, opTrue);
409 _ilg.Emit(OpCodes.Brtrue, labEnd);
411 //store the value of the left value before emitting b.Right to empty the evaluation stack
412 LocalBuilder locLeft = GetLocal(b.Left.Type);
413 _ilg.Emit(OpCodes.Stloc, locLeft);
415 EmitExpression(b.Right);
416 //store the right value to local
417 LocalBuilder locRight = GetLocal(b.Right.Type);
418 _ilg.Emit(OpCodes.Stloc, locRight);
420 Debug.Assert(b.Method.IsStatic);
421 _ilg.Emit(OpCodes.Ldloc, locLeft);
422 _ilg.Emit(OpCodes.Ldloc, locRight);
423 if ((flags & CompilationFlags.EmitAsTailCallMask) == CompilationFlags.EmitAsTail) {
424 _ilg.Emit(OpCodes.Tailcall);
426 _ilg.Emit(OpCodes.Call, b.Method);
429 _ilg.MarkLabel(labEnd);
432 private void EmitOrElseBinaryExpression(Expression expr, CompilationFlags flags) {
433 BinaryExpression b = (BinaryExpression)expr;
435 if (b.Method != null && !b.IsLiftedLogical) {
436 EmitMethodOrElse(b, flags);
437 } else if (b.Left.Type == typeof(bool?)) {
439 } else if (b.IsLiftedLogical) {
440 EmitExpression(b.ReduceUserdefinedLifted());
442 EmitUnliftedOrElse(b);
448 #region Optimized branching
451 /// Emits the expression and then either brtrue/brfalse to the label.
453 /// <param name="branchValue">True for brtrue, false for brfalse.</param>
454 /// <param name="node">The expression to emit.</param>
455 /// <param name="label">The label to conditionally branch to.</param>
457 /// This function optimizes equality and short circuiting logical
458 /// operators to avoid double-branching, minimize instruction count,
459 /// and generate similar IL to the C# compiler. This is important for
460 /// the JIT to optimize patterns like:
461 /// x != null AndAlso x.GetType() == typeof(SomeType)
463 /// One optimization we don't do: we always emits at least one
464 /// conditional branch to the label, and always possibly falls through,
465 /// even if we know if the branch will always succeed or always fail.
466 /// We do this to avoid generating unreachable code, which is fine for
467 /// the CLR JIT, but doesn't verify with peverify.
469 /// This kind of optimization could be implemented safely, by doing
470 /// constant folding over conditionals and logical expressions at the
473 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
474 private void EmitExpressionAndBranch(bool branchValue, Expression node, Label label) {
475 CompilationFlags startEmitted = EmitExpressionStart(node);
477 if (node.Type == typeof(bool)) {
478 switch (node.NodeType) {
479 case ExpressionType.Not:
480 EmitBranchNot(branchValue, (UnaryExpression)node, label);
482 case ExpressionType.AndAlso:
483 case ExpressionType.OrElse:
484 EmitBranchLogical(branchValue, (BinaryExpression)node, label);
486 case ExpressionType.Block:
487 EmitBranchBlock(branchValue, (BlockExpression)node, label);
489 case ExpressionType.Equal:
490 case ExpressionType.NotEqual:
491 EmitBranchComparison(branchValue, (BinaryExpression)node, label);
495 EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
496 EmitBranchOp(branchValue, label);
498 EmitExpressionEnd(startEmitted);
502 private void EmitBranchOp(bool branch, Label label) {
503 _ilg.Emit(branch ? OpCodes.Brtrue : OpCodes.Brfalse, label);
506 private void EmitBranchNot(bool branch, UnaryExpression node, Label label) {
507 if (node.Method != null) {
508 EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
509 EmitBranchOp(branch, label);
512 EmitExpressionAndBranch(!branch, node.Operand, label);
515 private void EmitBranchComparison(bool branch, BinaryExpression node, Label label) {
516 Debug.Assert(node.NodeType == ExpressionType.Equal || node.NodeType == ExpressionType.NotEqual);
517 Debug.Assert(!node.IsLiftedToNull);
519 // To share code paths, we want to treat NotEqual as an inverted Equal
520 bool branchWhenEqual = branch == (node.NodeType == ExpressionType.Equal);
522 if (node.Method != null) {
523 EmitBinaryMethod(node, CompilationFlags.EmitAsNoTail);
524 // EmitBinaryMethod takes into account the Equal/NotEqual
525 // node kind, so use the original branch value
526 EmitBranchOp(branch, label);
527 } else if (ConstantCheck.IsNull(node.Left)) {
528 if (TypeUtils.IsNullableType(node.Right.Type)) {
529 EmitAddress(node.Right, node.Right.Type);
530 _ilg.EmitHasValue(node.Right.Type);
532 Debug.Assert(!node.Right.Type.IsValueType);
533 EmitExpression(GetEqualityOperand(node.Right));
535 EmitBranchOp(!branchWhenEqual, label);
536 } else if (ConstantCheck.IsNull(node.Right)) {
537 if (TypeUtils.IsNullableType(node.Left.Type)) {
538 EmitAddress(node.Left, node.Left.Type);
539 _ilg.EmitHasValue(node.Left.Type);
541 Debug.Assert(!node.Left.Type.IsValueType);
542 EmitExpression(GetEqualityOperand(node.Left));
544 EmitBranchOp(!branchWhenEqual, label);
545 } else if (TypeUtils.IsNullableType(node.Left.Type) || TypeUtils.IsNullableType(node.Right.Type)) {
546 EmitBinaryExpression(node);
547 // EmitBinaryExpression takes into account the Equal/NotEqual
548 // node kind, so use the original branch value
549 EmitBranchOp(branch, label);
551 EmitExpression(GetEqualityOperand(node.Left));
552 EmitExpression(GetEqualityOperand(node.Right));
553 if (branchWhenEqual) {
554 _ilg.Emit(OpCodes.Beq, label);
556 _ilg.Emit(OpCodes.Ceq);
557 _ilg.Emit(OpCodes.Brfalse, label);
562 // For optimized Equal/NotEqual, we can eliminate reference
563 // conversions. IL allows comparing managed pointers regardless of
564 // type. See ECMA-335 "Binary Comparison or Branch Operations", in
565 // Partition III, Section 1.5 Table 4.
566 private static Expression GetEqualityOperand(Expression expression) {
567 if (expression.NodeType == ExpressionType.Convert) {
568 var convert = (UnaryExpression)expression;
569 if (TypeUtils.AreReferenceAssignable(convert.Type, convert.Operand.Type)) {
570 return convert.Operand;
576 private void EmitBranchLogical(bool branch, BinaryExpression node, Label label) {
577 Debug.Assert(node.NodeType == ExpressionType.AndAlso || node.NodeType == ExpressionType.OrElse);
578 Debug.Assert(!node.IsLiftedToNull);
580 if (node.Method != null || node.IsLifted) {
581 EmitExpression(node);
582 EmitBranchOp(branch, label);
587 bool isAnd = node.NodeType == ExpressionType.AndAlso;
589 // To share code, we make the following substitutions:
590 // if (!(left || right)) branch value
592 // if (!left && !right) branch value
594 // if (!(left && right)) branch value
596 // if (!left || !right) branch value
598 // The observation is that "brtrue(x && y)" has the same codegen as
599 // "brfalse(x || y)" except the branches have the opposite sign.
600 // Same for "brfalse(x && y)" and "brtrue(x || y)".
602 if (branch == isAnd) {
603 EmitBranchAnd(branch, node, label);
605 EmitBranchOr(branch, node, label);
609 // Generates optimized AndAlso with branch == true
610 // or optimized OrElse with branch == false
611 private void EmitBranchAnd(bool branch, BinaryExpression node, Label label) {
613 // if (right) branch label
616 Label endif = _ilg.DefineLabel();
617 EmitExpressionAndBranch(!branch, node.Left, endif);
618 EmitExpressionAndBranch(branch, node.Right, label);
619 _ilg.MarkLabel(endif);
622 // Generates optimized OrElse with branch == true
623 // or optimized AndAlso with branch == false
624 private void EmitBranchOr(bool branch, BinaryExpression node, Label label) {
625 // if (left OR right) branch label
627 EmitExpressionAndBranch(branch, node.Left, label);
628 EmitExpressionAndBranch(branch, node.Right, label);
631 private void EmitBranchBlock(bool branch, BlockExpression node, Label label) {
634 int count = node.ExpressionCount;
635 for (int i = 0; i < count - 1; i++) {
636 EmitExpressionAsVoid(node.GetExpression(i));
638 EmitExpressionAndBranch(branch, node.GetExpression(count - 1), label);