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 16 using System; 17 using System.Collections.Generic; 18 using System.Diagnostics; 19 using System.Dynamic.Utils; 20 using System.Reflection; 21 using System.Reflection.Emit; 22 23 #if SILVERLIGHT 24 using System.Core; 25 #endif 26 27 #if CLR2 28 namespace Microsoft.Scripting.Ast.Compiler { 29 #else 30 namespace System.Linq.Expressions.Compiler { 31 #endif 32 partial class LambdaCompiler { 33 EmitBinaryExpression(Expression expr)34 private void EmitBinaryExpression(Expression expr) { 35 EmitBinaryExpression(expr, CompilationFlags.EmitAsNoTail); 36 } 37 EmitBinaryExpression(Expression expr, CompilationFlags flags)38 private void EmitBinaryExpression(Expression expr, CompilationFlags flags) { 39 BinaryExpression b = (BinaryExpression)expr; 40 41 Debug.Assert(b.NodeType != ExpressionType.AndAlso && b.NodeType != ExpressionType.OrElse && b.NodeType != ExpressionType.Coalesce); 42 43 if (b.Method != null) { 44 EmitBinaryMethod(b, flags); 45 return; 46 } 47 48 // For EQ and NE, if there is a user-specified method, use it. 49 // Otherwise implement the C# semantics that allow equality 50 // comparisons on non-primitive nullable structs that don't 51 // overload "==" 52 if ((b.NodeType == ExpressionType.Equal || b.NodeType == ExpressionType.NotEqual) && 53 (b.Type == typeof(bool) || b.Type == typeof(bool?))) { 54 55 // If we have x==null, x!=null, null==x or null!=x where x is 56 // nullable but not null, then generate a call to x.HasValue. 57 Debug.Assert(!b.IsLiftedToNull || b.Type == typeof(bool?)); 58 if (ConstantCheck.IsNull(b.Left) && !ConstantCheck.IsNull(b.Right) && TypeUtils.IsNullableType(b.Right.Type)) { 59 EmitNullEquality(b.NodeType, b.Right, b.IsLiftedToNull); 60 return; 61 } 62 if (ConstantCheck.IsNull(b.Right) && !ConstantCheck.IsNull(b.Left) && TypeUtils.IsNullableType(b.Left.Type)) { 63 EmitNullEquality(b.NodeType, b.Left, b.IsLiftedToNull); 64 return; 65 } 66 67 // For EQ and NE, we can avoid some conversions if we're 68 // ultimately just comparing two managed pointers. 69 EmitExpression(GetEqualityOperand(b.Left)); 70 EmitExpression(GetEqualityOperand(b.Right)); 71 } else { 72 // Otherwise generate it normally 73 EmitExpression(b.Left); 74 EmitExpression(b.Right); 75 } 76 77 EmitBinaryOperator(b.NodeType, b.Left.Type, b.Right.Type, b.Type, b.IsLiftedToNull); 78 } 79 80 EmitNullEquality(ExpressionType op, Expression e, bool isLiftedToNull)81 private void EmitNullEquality(ExpressionType op, Expression e, bool isLiftedToNull) { 82 Debug.Assert(TypeUtils.IsNullableType(e.Type)); 83 Debug.Assert(op == ExpressionType.Equal || op == ExpressionType.NotEqual); 84 // If we are lifted to null then just evaluate the expression for its side effects, discard, 85 // and generate null. If we are not lifted to null then generate a call to HasValue. 86 if (isLiftedToNull) { 87 EmitExpressionAsVoid(e); 88 _ilg.EmitDefault(typeof(bool?)); 89 } else { 90 EmitAddress(e, e.Type); 91 _ilg.EmitHasValue(e.Type); 92 if (op == ExpressionType.Equal) { 93 _ilg.Emit(OpCodes.Ldc_I4_0); 94 _ilg.Emit(OpCodes.Ceq); 95 } 96 } 97 } 98 99 EmitBinaryMethod(BinaryExpression b, CompilationFlags flags)100 private void EmitBinaryMethod(BinaryExpression b, CompilationFlags flags) { 101 if (b.IsLifted) { 102 ParameterExpression p1 = Expression.Variable(TypeUtils.GetNonNullableType(b.Left.Type), null); 103 ParameterExpression p2 = Expression.Variable(TypeUtils.GetNonNullableType(b.Right.Type), null); 104 MethodCallExpression mc = Expression.Call(null, b.Method, p1, p2); 105 Type resultType = null; 106 if (b.IsLiftedToNull) { 107 resultType = TypeUtils.GetNullableType(mc.Type); 108 } else { 109 switch (b.NodeType) { 110 case ExpressionType.Equal: 111 case ExpressionType.NotEqual: 112 case ExpressionType.LessThan: 113 case ExpressionType.LessThanOrEqual: 114 case ExpressionType.GreaterThan: 115 case ExpressionType.GreaterThanOrEqual: 116 if (mc.Type != typeof(bool)) { 117 throw Error.ArgumentMustBeBoolean(); 118 } 119 resultType = typeof(bool); 120 break; 121 default: 122 resultType = TypeUtils.GetNullableType(mc.Type); 123 break; 124 } 125 } 126 var variables = new ParameterExpression[] { p1, p2 }; 127 var arguments = new Expression[] { b.Left, b.Right }; 128 ValidateLift(variables, arguments); 129 EmitLift(b.NodeType, resultType, mc, variables, arguments); 130 } else { 131 EmitMethodCallExpression(Expression.Call(null, b.Method, b.Left, b.Right), flags); 132 } 133 } 134 135 EmitBinaryOperator(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull)136 private void EmitBinaryOperator(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) { 137 bool leftIsNullable = TypeUtils.IsNullableType(leftType); 138 bool rightIsNullable = TypeUtils.IsNullableType(rightType); 139 140 switch (op) { 141 case ExpressionType.ArrayIndex: 142 if (rightType != typeof(int)) { 143 throw ContractUtils.Unreachable; 144 } 145 _ilg.EmitLoadElement(leftType.GetElementType()); 146 return; 147 case ExpressionType.Coalesce: 148 throw Error.UnexpectedCoalesceOperator(); 149 } 150 151 if (leftIsNullable || rightIsNullable) { 152 EmitLiftedBinaryOp(op, leftType, rightType, resultType, liftedToNull); 153 } else { 154 EmitUnliftedBinaryOp(op, leftType, rightType); 155 EmitConvertArithmeticResult(op, resultType); 156 } 157 } 158 159 160 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] EmitUnliftedBinaryOp(ExpressionType op, Type leftType, Type rightType)161 private void EmitUnliftedBinaryOp(ExpressionType op, Type leftType, Type rightType) { 162 Debug.Assert(!TypeUtils.IsNullableType(leftType)); 163 Debug.Assert(!TypeUtils.IsNullableType(rightType)); 164 165 if (op == ExpressionType.Equal || op == ExpressionType.NotEqual) { 166 EmitUnliftedEquality(op, leftType); 167 return; 168 } 169 if (!leftType.IsPrimitive) { 170 throw Error.OperatorNotImplementedForType(op, leftType); 171 } 172 switch (op) { 173 case ExpressionType.Add: 174 _ilg.Emit(OpCodes.Add); 175 break; 176 case ExpressionType.AddChecked: 177 if (TypeUtils.IsFloatingPoint(leftType)) { 178 _ilg.Emit(OpCodes.Add); 179 } else if (TypeUtils.IsUnsigned(leftType)) { 180 _ilg.Emit(OpCodes.Add_Ovf_Un); 181 } else { 182 _ilg.Emit(OpCodes.Add_Ovf); 183 } 184 break; 185 case ExpressionType.Subtract: 186 _ilg.Emit(OpCodes.Sub); 187 break; 188 case ExpressionType.SubtractChecked: 189 if (TypeUtils.IsFloatingPoint(leftType)) { 190 _ilg.Emit(OpCodes.Sub); 191 } else if (TypeUtils.IsUnsigned(leftType)) { 192 _ilg.Emit(OpCodes.Sub_Ovf_Un); 193 } else { 194 _ilg.Emit(OpCodes.Sub_Ovf); 195 } 196 break; 197 case ExpressionType.Multiply: 198 _ilg.Emit(OpCodes.Mul); 199 break; 200 case ExpressionType.MultiplyChecked: 201 if (TypeUtils.IsFloatingPoint(leftType)) { 202 _ilg.Emit(OpCodes.Mul); 203 } else if (TypeUtils.IsUnsigned(leftType)) { 204 _ilg.Emit(OpCodes.Mul_Ovf_Un); 205 } else { 206 _ilg.Emit(OpCodes.Mul_Ovf); 207 } 208 break; 209 case ExpressionType.Divide: 210 if (TypeUtils.IsUnsigned(leftType)) { 211 _ilg.Emit(OpCodes.Div_Un); 212 } else { 213 _ilg.Emit(OpCodes.Div); 214 } 215 break; 216 case ExpressionType.Modulo: 217 if (TypeUtils.IsUnsigned(leftType)) { 218 _ilg.Emit(OpCodes.Rem_Un); 219 } else { 220 _ilg.Emit(OpCodes.Rem); 221 } 222 break; 223 case ExpressionType.And: 224 case ExpressionType.AndAlso: 225 _ilg.Emit(OpCodes.And); 226 break; 227 case ExpressionType.Or: 228 case ExpressionType.OrElse: 229 _ilg.Emit(OpCodes.Or); 230 break; 231 case ExpressionType.LessThan: 232 if (TypeUtils.IsUnsigned(leftType)) { 233 _ilg.Emit(OpCodes.Clt_Un); 234 } else { 235 _ilg.Emit(OpCodes.Clt); 236 } 237 break; 238 case ExpressionType.LessThanOrEqual: { 239 Label labFalse = _ilg.DefineLabel(); 240 Label labEnd = _ilg.DefineLabel(); 241 if (TypeUtils.IsUnsigned(leftType)) { 242 _ilg.Emit(OpCodes.Ble_Un_S, labFalse); 243 } else { 244 _ilg.Emit(OpCodes.Ble_S, labFalse); 245 } 246 _ilg.Emit(OpCodes.Ldc_I4_0); 247 _ilg.Emit(OpCodes.Br_S, labEnd); 248 _ilg.MarkLabel(labFalse); 249 _ilg.Emit(OpCodes.Ldc_I4_1); 250 _ilg.MarkLabel(labEnd); 251 } 252 break; 253 case ExpressionType.GreaterThan: 254 if (TypeUtils.IsUnsigned(leftType)) { 255 _ilg.Emit(OpCodes.Cgt_Un); 256 } else { 257 _ilg.Emit(OpCodes.Cgt); 258 } 259 break; 260 case ExpressionType.GreaterThanOrEqual: { 261 Label labFalse = _ilg.DefineLabel(); 262 Label labEnd = _ilg.DefineLabel(); 263 if (TypeUtils.IsUnsigned(leftType)) { 264 _ilg.Emit(OpCodes.Bge_Un_S, labFalse); 265 } else { 266 _ilg.Emit(OpCodes.Bge_S, labFalse); 267 } 268 _ilg.Emit(OpCodes.Ldc_I4_0); 269 _ilg.Emit(OpCodes.Br_S, labEnd); 270 _ilg.MarkLabel(labFalse); 271 _ilg.Emit(OpCodes.Ldc_I4_1); 272 _ilg.MarkLabel(labEnd); 273 } 274 break; 275 case ExpressionType.ExclusiveOr: 276 _ilg.Emit(OpCodes.Xor); 277 break; 278 case ExpressionType.LeftShift: 279 if (rightType != typeof(int)) { 280 throw ContractUtils.Unreachable; 281 } 282 _ilg.Emit(OpCodes.Shl); 283 break; 284 case ExpressionType.RightShift: 285 if (rightType != typeof(int)) { 286 throw ContractUtils.Unreachable; 287 } 288 if (TypeUtils.IsUnsigned(leftType)) { 289 _ilg.Emit(OpCodes.Shr_Un); 290 } else { 291 _ilg.Emit(OpCodes.Shr); 292 } 293 break; 294 default: 295 throw Error.UnhandledBinary(op); 296 } 297 } 298 299 // Binary/unary operations on 8 and 16 bit operand types will leave a 300 // 32-bit value on the stack, because that's how IL works. For these 301 // cases, we need to cast it back to the resultType, possibly using a 302 // checked conversion if the original operator was convert EmitConvertArithmeticResult(ExpressionType op, Type resultType)303 private void EmitConvertArithmeticResult(ExpressionType op, Type resultType) { 304 Debug.Assert(!resultType.IsNullableType()); 305 306 switch (Type.GetTypeCode(resultType)) { 307 case TypeCode.Byte: 308 _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1); 309 break; 310 case TypeCode.SByte: 311 _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1); 312 break; 313 case TypeCode.UInt16: 314 _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2); 315 break; 316 case TypeCode.Int16: 317 _ilg.Emit(IsChecked(op) ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2); 318 break; 319 } 320 } 321 EmitUnliftedEquality(ExpressionType op, Type type)322 private void EmitUnliftedEquality(ExpressionType op, Type type) { 323 Debug.Assert(op == ExpressionType.Equal || op == ExpressionType.NotEqual); 324 if (!type.IsPrimitive && type.IsValueType && !type.IsEnum) { 325 throw Error.OperatorNotImplementedForType(op, type); 326 } 327 _ilg.Emit(OpCodes.Ceq); 328 if (op == ExpressionType.NotEqual) { 329 _ilg.Emit(OpCodes.Ldc_I4_0); 330 _ilg.Emit(OpCodes.Ceq); 331 } 332 } 333 334 335 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] EmitLiftedBinaryOp(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull)336 private void EmitLiftedBinaryOp(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) { 337 Debug.Assert(TypeUtils.IsNullableType(leftType) || TypeUtils.IsNullableType(rightType)); 338 switch (op) { 339 case ExpressionType.And: 340 if (leftType == typeof(bool?)) { 341 EmitLiftedBooleanAnd(); 342 } else { 343 EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType); 344 } 345 break; 346 case ExpressionType.Or: 347 if (leftType == typeof(bool?)) { 348 EmitLiftedBooleanOr(); 349 } else { 350 EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType); 351 } 352 break; 353 case ExpressionType.ExclusiveOr: 354 case ExpressionType.Add: 355 case ExpressionType.AddChecked: 356 case ExpressionType.Subtract: 357 case ExpressionType.SubtractChecked: 358 case ExpressionType.Multiply: 359 case ExpressionType.MultiplyChecked: 360 case ExpressionType.Divide: 361 case ExpressionType.Modulo: 362 case ExpressionType.LeftShift: 363 case ExpressionType.RightShift: 364 EmitLiftedBinaryArithmetic(op, leftType, rightType, resultType); 365 break; 366 case ExpressionType.LessThan: 367 case ExpressionType.LessThanOrEqual: 368 case ExpressionType.GreaterThan: 369 case ExpressionType.GreaterThanOrEqual: 370 case ExpressionType.Equal: 371 case ExpressionType.NotEqual: 372 EmitLiftedRelational(op, leftType, rightType, resultType, liftedToNull); 373 break; 374 case ExpressionType.AndAlso: 375 case ExpressionType.OrElse: 376 default: 377 throw ContractUtils.Unreachable; 378 } 379 } 380 381 EmitLiftedRelational(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull)382 private void EmitLiftedRelational(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull) { 383 Debug.Assert(TypeUtils.IsNullableType(leftType)); 384 385 Label shortCircuit = _ilg.DefineLabel(); 386 LocalBuilder locLeft = GetLocal(leftType); 387 LocalBuilder locRight = GetLocal(rightType); 388 389 // store values (reverse order since they are already on the stack) 390 _ilg.Emit(OpCodes.Stloc, locRight); 391 _ilg.Emit(OpCodes.Stloc, locLeft); 392 393 if (op == ExpressionType.Equal) { 394 // test for both null -> true 395 _ilg.Emit(OpCodes.Ldloca, locLeft); 396 _ilg.EmitHasValue(leftType); 397 _ilg.Emit(OpCodes.Ldc_I4_0); 398 _ilg.Emit(OpCodes.Ceq); 399 _ilg.Emit(OpCodes.Ldloca, locRight); 400 _ilg.EmitHasValue(rightType); 401 _ilg.Emit(OpCodes.Ldc_I4_0); 402 _ilg.Emit(OpCodes.Ceq); 403 _ilg.Emit(OpCodes.And); 404 _ilg.Emit(OpCodes.Dup); 405 _ilg.Emit(OpCodes.Brtrue_S, shortCircuit); 406 _ilg.Emit(OpCodes.Pop); 407 408 // test for either is null -> false 409 _ilg.Emit(OpCodes.Ldloca, locLeft); 410 _ilg.EmitHasValue(leftType); 411 _ilg.Emit(OpCodes.Ldloca, locRight); 412 _ilg.EmitHasValue(rightType); 413 _ilg.Emit(OpCodes.And); 414 415 _ilg.Emit(OpCodes.Dup); 416 _ilg.Emit(OpCodes.Brfalse_S, shortCircuit); 417 _ilg.Emit(OpCodes.Pop); 418 } else if (op == ExpressionType.NotEqual) { 419 // test for both null -> false 420 _ilg.Emit(OpCodes.Ldloca, locLeft); 421 _ilg.EmitHasValue(leftType); 422 _ilg.Emit(OpCodes.Ldloca, locRight); 423 _ilg.EmitHasValue(rightType); 424 _ilg.Emit(OpCodes.Or); 425 _ilg.Emit(OpCodes.Dup); 426 _ilg.Emit(OpCodes.Brfalse_S, shortCircuit); 427 _ilg.Emit(OpCodes.Pop); 428 429 // test for either is null -> true 430 _ilg.Emit(OpCodes.Ldloca, locLeft); 431 _ilg.EmitHasValue(leftType); 432 _ilg.Emit(OpCodes.Ldc_I4_0); 433 _ilg.Emit(OpCodes.Ceq); 434 _ilg.Emit(OpCodes.Ldloca, locRight); 435 _ilg.EmitHasValue(rightType); 436 _ilg.Emit(OpCodes.Ldc_I4_0); 437 _ilg.Emit(OpCodes.Ceq); 438 _ilg.Emit(OpCodes.Or); 439 _ilg.Emit(OpCodes.Dup); 440 _ilg.Emit(OpCodes.Brtrue_S, shortCircuit); 441 _ilg.Emit(OpCodes.Pop); 442 } else { 443 // test for either is null -> false 444 _ilg.Emit(OpCodes.Ldloca, locLeft); 445 _ilg.EmitHasValue(leftType); 446 _ilg.Emit(OpCodes.Ldloca, locRight); 447 _ilg.EmitHasValue(rightType); 448 _ilg.Emit(OpCodes.And); 449 _ilg.Emit(OpCodes.Dup); 450 _ilg.Emit(OpCodes.Brfalse_S, shortCircuit); 451 _ilg.Emit(OpCodes.Pop); 452 } 453 454 // do op on values 455 _ilg.Emit(OpCodes.Ldloca, locLeft); 456 _ilg.EmitGetValueOrDefault(leftType); 457 _ilg.Emit(OpCodes.Ldloca, locRight); 458 _ilg.EmitGetValueOrDefault(rightType); 459 460 //RELEASING locLeft locRight 461 FreeLocal(locLeft); 462 FreeLocal(locRight); 463 464 EmitBinaryOperator( 465 op, 466 TypeUtils.GetNonNullableType(leftType), 467 TypeUtils.GetNonNullableType(rightType), 468 TypeUtils.GetNonNullableType(resultType), 469 false 470 ); 471 472 if (!liftedToNull) { 473 _ilg.MarkLabel(shortCircuit); 474 } 475 476 if (!TypeUtils.AreEquivalent(resultType, TypeUtils.GetNonNullableType(resultType))) { 477 _ilg.EmitConvertToType(TypeUtils.GetNonNullableType(resultType), resultType, true); 478 } 479 480 if (liftedToNull) { 481 Label labEnd = _ilg.DefineLabel(); 482 _ilg.Emit(OpCodes.Br, labEnd); 483 _ilg.MarkLabel(shortCircuit); 484 _ilg.Emit(OpCodes.Pop); 485 _ilg.Emit(OpCodes.Ldnull); 486 _ilg.Emit(OpCodes.Unbox_Any, resultType); 487 _ilg.MarkLabel(labEnd); 488 } 489 } 490 491 EmitLiftedBinaryArithmetic(ExpressionType op, Type leftType, Type rightType, Type resultType)492 private void EmitLiftedBinaryArithmetic(ExpressionType op, Type leftType, Type rightType, Type resultType) { 493 bool leftIsNullable = TypeUtils.IsNullableType(leftType); 494 bool rightIsNullable = TypeUtils.IsNullableType(rightType); 495 496 Debug.Assert(leftIsNullable || rightIsNullable); 497 498 Label labIfNull = _ilg.DefineLabel(); 499 Label labEnd = _ilg.DefineLabel(); 500 LocalBuilder locLeft = GetLocal(leftType); 501 LocalBuilder locRight = GetLocal(rightType); 502 LocalBuilder locResult = GetLocal(resultType); 503 504 // store values (reverse order since they are already on the stack) 505 _ilg.Emit(OpCodes.Stloc, locRight); 506 _ilg.Emit(OpCodes.Stloc, locLeft); 507 508 // test for null 509 // use short circuiting 510 if (leftIsNullable) { 511 _ilg.Emit(OpCodes.Ldloca, locLeft); 512 _ilg.EmitHasValue(leftType); 513 _ilg.Emit(OpCodes.Brfalse_S, labIfNull); 514 } 515 if (rightIsNullable) { 516 _ilg.Emit(OpCodes.Ldloca, locRight); 517 _ilg.EmitHasValue(rightType); 518 _ilg.Emit(OpCodes.Brfalse_S, labIfNull); 519 } 520 521 // do op on values 522 if (leftIsNullable) { 523 _ilg.Emit(OpCodes.Ldloca, locLeft); 524 _ilg.EmitGetValueOrDefault(leftType); 525 } else { 526 _ilg.Emit(OpCodes.Ldloc, locLeft); 527 } 528 529 if (rightIsNullable) { 530 _ilg.Emit(OpCodes.Ldloca, locRight); 531 _ilg.EmitGetValueOrDefault(rightType); 532 } else { 533 _ilg.Emit(OpCodes.Ldloc, locRight); 534 } 535 536 //RELEASING locLeft locRight 537 FreeLocal(locLeft); 538 FreeLocal(locRight); 539 540 EmitBinaryOperator(op, TypeUtils.GetNonNullableType(leftType), TypeUtils.GetNonNullableType(rightType), TypeUtils.GetNonNullableType(resultType), false); 541 542 // construct result type 543 ConstructorInfo ci = resultType.GetConstructor(new Type[] { TypeUtils.GetNonNullableType(resultType) }); 544 _ilg.Emit(OpCodes.Newobj, ci); 545 _ilg.Emit(OpCodes.Stloc, locResult); 546 _ilg.Emit(OpCodes.Br_S, labEnd); 547 548 // if null then create a default one 549 _ilg.MarkLabel(labIfNull); 550 _ilg.Emit(OpCodes.Ldloca, locResult); 551 _ilg.Emit(OpCodes.Initobj, resultType); 552 553 _ilg.MarkLabel(labEnd); 554 555 _ilg.Emit(OpCodes.Ldloc, locResult); 556 557 //RELEASING locResult 558 FreeLocal(locResult); 559 } 560 561 EmitLiftedBooleanAnd()562 private void EmitLiftedBooleanAnd() { 563 Type type = typeof(bool?); 564 Label labComputeRight = _ilg.DefineLabel(); 565 Label labReturnFalse = _ilg.DefineLabel(); 566 Label labReturnNull = _ilg.DefineLabel(); 567 Label labReturnValue = _ilg.DefineLabel(); 568 Label labExit = _ilg.DefineLabel(); 569 570 // store values (reverse order since they are already on the stack) 571 LocalBuilder locLeft = GetLocal(type); 572 LocalBuilder locRight = GetLocal(type); 573 _ilg.Emit(OpCodes.Stloc, locRight); 574 _ilg.Emit(OpCodes.Stloc, locLeft); 575 576 // compute left 577 _ilg.Emit(OpCodes.Ldloca, locLeft); 578 _ilg.EmitHasValue(type); 579 _ilg.Emit(OpCodes.Brfalse, labComputeRight); 580 _ilg.Emit(OpCodes.Ldloca, locLeft); 581 _ilg.EmitGetValueOrDefault(type); 582 _ilg.Emit(OpCodes.Ldc_I4_0); 583 _ilg.Emit(OpCodes.Ceq); 584 _ilg.Emit(OpCodes.Brtrue, labReturnFalse); 585 586 // compute right 587 _ilg.MarkLabel(labComputeRight); 588 _ilg.Emit(OpCodes.Ldloca, locRight); 589 _ilg.EmitHasValue(type); 590 _ilg.Emit(OpCodes.Brfalse_S, labReturnNull); 591 _ilg.Emit(OpCodes.Ldloca, locRight); 592 593 //RELEASING locRight 594 FreeLocal(locRight); 595 596 _ilg.EmitGetValueOrDefault(type); 597 _ilg.Emit(OpCodes.Ldc_I4_0); 598 _ilg.Emit(OpCodes.Ceq); 599 _ilg.Emit(OpCodes.Brtrue_S, labReturnFalse); 600 601 // check left for null again 602 _ilg.Emit(OpCodes.Ldloca, locLeft); 603 _ilg.EmitHasValue(type); 604 _ilg.Emit(OpCodes.Brfalse, labReturnNull); 605 606 // return true 607 _ilg.Emit(OpCodes.Ldc_I4_1); 608 _ilg.Emit(OpCodes.Br_S, labReturnValue); 609 610 // return false 611 _ilg.MarkLabel(labReturnFalse); 612 _ilg.Emit(OpCodes.Ldc_I4_0); 613 _ilg.Emit(OpCodes.Br_S, labReturnValue); 614 615 _ilg.MarkLabel(labReturnValue); 616 ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) }); 617 _ilg.Emit(OpCodes.Newobj, ci); 618 _ilg.Emit(OpCodes.Stloc, locLeft); 619 _ilg.Emit(OpCodes.Br, labExit); 620 621 // return null 622 _ilg.MarkLabel(labReturnNull); 623 _ilg.Emit(OpCodes.Ldloca, locLeft); 624 _ilg.Emit(OpCodes.Initobj, type); 625 626 _ilg.MarkLabel(labExit); 627 _ilg.Emit(OpCodes.Ldloc, locLeft); 628 629 //RELEASING locLeft 630 FreeLocal(locLeft); 631 } 632 633 EmitLiftedBooleanOr()634 private void EmitLiftedBooleanOr() { 635 Type type = typeof(bool?); 636 Label labComputeRight = _ilg.DefineLabel(); 637 Label labReturnTrue = _ilg.DefineLabel(); 638 Label labReturnNull = _ilg.DefineLabel(); 639 Label labReturnValue = _ilg.DefineLabel(); 640 Label labExit = _ilg.DefineLabel(); 641 642 // store values (reverse order since they are already on the stack) 643 LocalBuilder locLeft = GetLocal(type); 644 LocalBuilder locRight = GetLocal(type); 645 _ilg.Emit(OpCodes.Stloc, locRight); 646 _ilg.Emit(OpCodes.Stloc, locLeft); 647 648 // compute left 649 _ilg.Emit(OpCodes.Ldloca, locLeft); 650 _ilg.EmitHasValue(type); 651 _ilg.Emit(OpCodes.Brfalse, labComputeRight); 652 _ilg.Emit(OpCodes.Ldloca, locLeft); 653 _ilg.EmitGetValueOrDefault(type); 654 _ilg.Emit(OpCodes.Ldc_I4_0); 655 _ilg.Emit(OpCodes.Ceq); 656 _ilg.Emit(OpCodes.Brfalse, labReturnTrue); 657 658 // compute right 659 _ilg.MarkLabel(labComputeRight); 660 _ilg.Emit(OpCodes.Ldloca, locRight); 661 _ilg.EmitHasValue(type); 662 _ilg.Emit(OpCodes.Brfalse_S, labReturnNull); 663 _ilg.Emit(OpCodes.Ldloca, locRight); 664 665 //RELEASING locRight 666 FreeLocal(locRight); 667 668 _ilg.EmitGetValueOrDefault(type); 669 _ilg.Emit(OpCodes.Ldc_I4_0); 670 _ilg.Emit(OpCodes.Ceq); 671 _ilg.Emit(OpCodes.Brfalse_S, labReturnTrue); 672 673 // check left for null again 674 _ilg.Emit(OpCodes.Ldloca, locLeft); 675 _ilg.EmitHasValue(type); 676 _ilg.Emit(OpCodes.Brfalse, labReturnNull); 677 678 // return false 679 _ilg.Emit(OpCodes.Ldc_I4_0); 680 _ilg.Emit(OpCodes.Br_S, labReturnValue); 681 682 // return true 683 _ilg.MarkLabel(labReturnTrue); 684 _ilg.Emit(OpCodes.Ldc_I4_1); 685 _ilg.Emit(OpCodes.Br_S, labReturnValue); 686 687 _ilg.MarkLabel(labReturnValue); 688 ConstructorInfo ci = type.GetConstructor(new Type[] { typeof(bool) }); 689 _ilg.Emit(OpCodes.Newobj, ci); 690 _ilg.Emit(OpCodes.Stloc, locLeft); 691 _ilg.Emit(OpCodes.Br, labExit); 692 693 // return null 694 _ilg.MarkLabel(labReturnNull); 695 _ilg.Emit(OpCodes.Ldloca, locLeft); 696 _ilg.Emit(OpCodes.Initobj, type); 697 698 _ilg.MarkLabel(labExit); 699 _ilg.Emit(OpCodes.Ldloc, locLeft); 700 701 //RELEASING locLeft 702 FreeLocal(locLeft); 703 } 704 } 705 } 706