public override void Emit(EmitContext ec) { Label is_null_label = ec.DefineLabel (); Label end_label = ec.DefineLabel (); unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse, is_null_label); expr.Emit (ec); ec.Emit (OpCodes.Br, end_label); ec.MarkLabel (is_null_label); null_value.Emit (ec); ec.MarkLabel (end_label); }
public override void Emit (EmitContext ec) { Label end_label = ec.DefineLabel (); if (unwrap != null) { Label is_null_label = ec.DefineLabel (); unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse, is_null_label); left.Emit (ec); ec.Emit (OpCodes.Br, end_label); ec.MarkLabel (is_null_label); right.Emit (ec); ec.MarkLabel (end_label); return; } left.Emit (ec); ec.Emit (OpCodes.Dup); // Only to make verifier happy if (left.Type.IsGenericParameter) ec.Emit (OpCodes.Box, left.Type); ec.Emit (OpCodes.Brtrue, end_label); ec.Emit (OpCodes.Pop); right.Emit (ec); ec.MarkLabel (end_label); }
void EmitBitwiseBoolean (EmitContext ec) { Label load_left = ec.DefineLabel (); Label load_right = ec.DefineLabel (); Label end_label = ec.DefineLabel (); Label is_null_label = ec.DefineLabel (); bool or = Binary.Oper == Binary.Operator.BitwiseOr; // // Both operands are bool? types // if (UnwrapLeft != null && UnwrapRight != null) { if (ec.HasSet (BuilderContext.Options.AsyncBody) && Binary.Right.ContainsEmitWithAwait ()) { Left = Left.EmitToField (ec); Right = Right.EmitToField (ec); } Left.Emit (ec); ec.Emit (OpCodes.Brtrue_S, load_right); Right.Emit (ec); ec.Emit (OpCodes.Brtrue_S, load_left); UnwrapLeft.EmitCheck (ec); ec.Emit (OpCodes.Brfalse_S, load_right); // load left ec.MarkLabel (load_left); if (or) UnwrapRight.Load (ec); else UnwrapLeft.Load (ec); ec.Emit (OpCodes.Br_S, end_label); // load right ec.MarkLabel (load_right); if (or) UnwrapLeft.Load (ec); else UnwrapRight.Load (ec); ec.MarkLabel (end_label); return; } // // Faster version when one operand is bool // if (UnwrapLeft == null) { // // (bool, bool?) // // Optimizes remaining (false & bool?), (true | bool?) which are not easy to handle // in binary expression reduction // var c = Left as BoolConstant; if (c != null) { // Keep evaluation order UnwrapRight.Store (ec); ec.EmitInt (or ? 1 : 0); ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); } else if (Left.IsNull) { UnwrapRight.Emit (ec); ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label); UnwrapRight.Load (ec); ec.Emit (OpCodes.Br_S, end_label); ec.MarkLabel (is_null_label); LiftedNull.Create (type, loc).Emit (ec); } else { Left.Emit (ec); ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_right); ec.EmitInt (or ? 1 : 0); ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); ec.Emit (OpCodes.Br_S, end_label); ec.MarkLabel (load_right); UnwrapRight.Original.Emit (ec); } } else { // // (bool?, bool) // // Keep left-right evaluation order UnwrapLeft.Store (ec); // // Optimizes remaining (bool? & false), (bool? | true) which are not easy to handle // in binary expression reduction // var c = Right as BoolConstant; if (c != null) { ec.EmitInt (or ? 1 : 0); ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); } else if (Right.IsNull) { UnwrapLeft.Emit (ec); ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label); UnwrapLeft.Load (ec); ec.Emit (OpCodes.Br_S, end_label); ec.MarkLabel (is_null_label); LiftedNull.Create (type, loc).Emit (ec); } else { Right.Emit (ec); ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_right); ec.EmitInt (or ? 1 : 0); ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); ec.Emit (OpCodes.Br_S, end_label); ec.MarkLabel (load_right); UnwrapLeft.Load (ec); } } ec.MarkLabel (end_label); }
protected override void EmitOperation (EmitContext ec) { Label is_null_label = ec.DefineLabel (); Label end_label = ec.DefineLabel (); LocalTemporary lt = new LocalTemporary (type); // Value is on the stack lt.Store (ec); var call = new CallEmitter (); call.InstanceExpression = lt; call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null); ec.Emit (OpCodes.Brfalse, is_null_label); call = new CallEmitter (); call.InstanceExpression = lt; call.EmitPredefined (ec, NullableInfo.GetGetValueOrDefault (expr.Type), null); lt.Release (ec); base.EmitOperation (ec); ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); ec.Emit (OpCodes.Br_S, end_label); ec.MarkLabel (is_null_label); LiftedNull.Create (type, loc).Emit (ec); ec.MarkLabel (end_label); }
void EmitLeftLiftedToNullBinary (EmitContext ec) { var ig = ec.ig; var ret = ig.DefineLabel (); var done = ig.DefineLabel (); var left = ec.EmitStored (this.left); ec.EmitNullableHasValue (left); ig.Emit (OpCodes.Brfalse, ret); ec.EmitNullableGetValueOrDefault (left); ec.Emit (right); EmitBinaryOperator (ec); ec.EmitNullableNew (Type); ig.Emit (OpCodes.Br, done); ig.MarkLabel (ret); var temp = ig.DeclareLocal (Type); ec.EmitNullableInitialize (temp); ig.MarkLabel (done); }
void EmitCoalesce (EmitContext ec) { var ig = ec.ig; var done = ig.DefineLabel (); var load_right = ig.DefineLabel (); var left = ec.EmitStored (this.left); var left_is_nullable = left.LocalType.IsNullable (); if (left_is_nullable) ec.EmitNullableHasValue (left); else ec.EmitLoad (left); ig.Emit (OpCodes.Brfalse, load_right); if (left_is_nullable && !Type.IsNullable ()) ec.EmitNullableGetValue (left); else ec.EmitLoad (left); ig.Emit (OpCodes.Br, done); ig.MarkLabel (load_right); ec.Emit (this.right); ig.MarkLabel (done); }
// // Emits optimized equality or inequality operator when possible // void EmitEquality(EmitContext ec) { // // Either left or right is null // if (UnwrapLeft != null && Binary.Right.IsNull) // TODO: Optimize for EmitBranchable // // left.HasValue == false // { UnwrapLeft.EmitCheck(ec); if (Binary.Oper == Binary.Operator.Equality) { ec.EmitInt(0); ec.Emit(OpCodes.Ceq); } return; } if (UnwrapRight != null && Binary.Left.IsNull) { // // right.HasValue == false // UnwrapRight.EmitCheck(ec); if (Binary.Oper == Binary.Operator.Equality) { ec.EmitInt(0); ec.Emit(OpCodes.Ceq); } return; } Label dissimilar_label = ec.DefineLabel(); Label end_label = ec.DefineLabel(); if (UserOperator != null) { var left = Left; if (UnwrapLeft != null) { UnwrapLeft.EmitCheck(ec); } else { // Keep evaluation order same if (!(Left is VariableReference)) { Left.Emit(ec); var lt = new LocalTemporary(Left.Type); lt.Store(ec); left = lt; } } if (UnwrapRight != null) { UnwrapRight.EmitCheck(ec); if (UnwrapLeft != null) { ec.Emit(OpCodes.Bne_Un, dissimilar_label); Label compare_label = ec.DefineLabel(); UnwrapLeft.EmitCheck(ec); ec.Emit(OpCodes.Brtrue, compare_label); if (Binary.Oper == Binary.Operator.Equality) { ec.EmitInt(1); } else { ec.EmitInt(0); } ec.Emit(OpCodes.Br, end_label); ec.MarkLabel(compare_label); } else { ec.Emit(OpCodes.Brfalse, dissimilar_label); } } else { ec.Emit(OpCodes.Brfalse, dissimilar_label); } var args = new Arguments(2); args.Add(new Argument(left)); args.Add(new Argument(Right)); var call = new CallEmitter(); call.EmitPredefined(ec, UserOperator, args); } else { if (ec.HasSet(BuilderContext.Options.AsyncBody) && Binary.Right.ContainsEmitWithAwait()) { Left = Left.EmitToField(ec); Right = Right.EmitToField(ec); } // // Emit underlying value comparison first. // // For this code: int? a = 1; bool b = a == 1; // // We emit something similar to this. Expressions with side effects have local // variable created by Unwrap expression // // left.GetValueOrDefault () // right // bne.un.s dissimilar_label // left.HasValue // br.s end_label // dissimilar_label: // ldc.i4.0 // end_label: // Left.Emit(ec); Right.Emit(ec); ec.Emit(OpCodes.Bne_Un_S, dissimilar_label); // // Check both left and right expressions for Unwrap call in which // case we need to run get_HasValue() check because the type is // nullable and could have null value // if (UnwrapLeft != null) { UnwrapLeft.EmitCheck(ec); } if (UnwrapRight != null) { UnwrapRight.EmitCheck(ec); } if (UnwrapLeft != null && UnwrapRight != null) { if (Binary.Oper == Binary.Operator.Inequality) { ec.Emit(OpCodes.Xor); } else { ec.Emit(OpCodes.Ceq); } } else { if (Binary.Oper == Binary.Operator.Inequality) { ec.EmitInt(0); ec.Emit(OpCodes.Ceq); } } } ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(dissimilar_label); if (Binary.Oper == Binary.Operator.Inequality) { ec.EmitInt(1); } else { ec.EmitInt(0); } ec.MarkLabel(end_label); }
void EmitBitwiseBoolean (EmitContext ec) { Label load_left = ec.DefineLabel (); Label load_right = ec.DefineLabel (); Label end_label = ec.DefineLabel (); // null & value, null | value if (left_unwrap == null) { left_unwrap = right_unwrap; right_unwrap = null; right = left; } left_unwrap.Emit (ec); ec.Emit (OpCodes.Brtrue_S, load_right); // value & null, value | null if (right_unwrap != null) { right_unwrap.Emit (ec); ec.Emit (OpCodes.Brtrue_S, load_left); } left_unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse_S, load_right); // load left ec.MarkLabel (load_left); if (Oper == Operator.BitwiseAnd) { left_unwrap.Load (ec); } else { if (right_unwrap == null) { right.Emit (ec); if (right is EmptyConstantCast || right is EmptyCast) ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); } else { right_unwrap.Load (ec); right_unwrap = left_unwrap; } } ec.Emit (OpCodes.Br_S, end_label); // load right ec.MarkLabel (load_right); if (right_unwrap == null) { if (Oper == Operator.BitwiseAnd) { right.Emit (ec); if (right is EmptyConstantCast || right is EmptyCast) ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); } else { left_unwrap.Load (ec); } } else { right_unwrap.Load (ec); } ec.MarkLabel (end_label); }
public override void EmitBranchable(EmitContext ec, Label target, bool onTrue) { Emit(ec); ec.Emit(onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target); }
// // Emits optimized equality or inequality operator when possible // void EmitEquality(EmitContext ec) { // // Either left or right is null // if (left_unwrap != null && (IsRightNullLifted || right.IsNull)) { left_unwrap.EmitCheck(ec); if (Oper == Binary.Operator.Equality) { ec.Emit(OpCodes.Ldc_I4_0); ec.Emit(OpCodes.Ceq); } return; } if (right_unwrap != null && (IsLeftNullLifted || left.IsNull)) { right_unwrap.EmitCheck(ec); if (Oper == Binary.Operator.Equality) { ec.Emit(OpCodes.Ldc_I4_0); ec.Emit(OpCodes.Ceq); } return; } Label dissimilar_label = ec.DefineLabel(); Label end_label = ec.DefineLabel(); if (user_operator != null) { user_operator.Emit(ec); ec.Emit(Oper == Operator.Equality ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, dissimilar_label); } else { left.Emit(ec); right.Emit(ec); ec.Emit(OpCodes.Bne_Un_S, dissimilar_label); } if (left_unwrap != null) { left_unwrap.EmitCheck(ec); } if (right_unwrap != null) { right_unwrap.EmitCheck(ec); } if (left_unwrap != null && right_unwrap != null) { if (Oper == Operator.Inequality) { ec.Emit(OpCodes.Xor); } else { ec.Emit(OpCodes.Ceq); } } else { if (Oper == Operator.Inequality) { ec.Emit(OpCodes.Ldc_I4_0); ec.Emit(OpCodes.Ceq); } } ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(dissimilar_label); if (Oper == Operator.Inequality) { ec.Emit(OpCodes.Ldc_I4_1); } else { ec.Emit(OpCodes.Ldc_I4_0); } ec.MarkLabel(end_label); }
void EmitBitwiseBoolean(EmitContext ec) { Label load_left = ec.DefineLabel(); Label load_right = ec.DefineLabel(); Label end_label = ec.DefineLabel(); // null & value, null | value if (left_unwrap == null) { left_unwrap = right_unwrap; right_unwrap = null; right = left; } left_unwrap.Emit(ec); ec.Emit(OpCodes.Brtrue_S, load_right); // value & null, value | null if (right_unwrap != null) { right_unwrap.Emit(ec); ec.Emit(OpCodes.Brtrue_S, load_left); } left_unwrap.EmitCheck(ec); ec.Emit(OpCodes.Brfalse_S, load_right); // load left ec.MarkLabel(load_left); if (Oper == Operator.BitwiseAnd) { left_unwrap.Load(ec); } else { if (right_unwrap == null) { right.Emit(ec); if (right is EmptyConstantCast || right is EmptyCast) { ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); } } else { right_unwrap.Load(ec); right_unwrap = left_unwrap; } } ec.Emit(OpCodes.Br_S, end_label); // load right ec.MarkLabel(load_right); if (right_unwrap == null) { if (Oper == Operator.BitwiseAnd) { right.Emit(ec); if (right is EmptyConstantCast || right is EmptyCast) { ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); } } else { left_unwrap.Load(ec); } } else { right_unwrap.Load(ec); } ec.MarkLabel(end_label); }
public override void Emit(EmitContext ec) { child.Emit(ec); ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); }
void EmitBitwiseBoolean(EmitContext ec) { Label load_left = ec.DefineLabel(); Label load_right = ec.DefineLabel(); Label end_label = ec.DefineLabel(); Label is_null_label = ec.DefineLabel(); bool or = Binary.Oper == Binary.Operator.BitwiseOr; // // Both operands are bool? types // if ((UnwrapLeft != null && !Left.IsNull) && (UnwrapRight != null && !Right.IsNull)) { if (ec.HasSet(BuilderContext.Options.AsyncBody) && Binary.Right.ContainsEmitWithAwait()) { Left = Left.EmitToField(ec); Right = Right.EmitToField(ec); } else { UnwrapLeft.Store(ec); UnwrapRight.Store(ec); } Left.Emit(ec); ec.Emit(OpCodes.Brtrue_S, load_right); Right.Emit(ec); ec.Emit(OpCodes.Brtrue_S, load_left); UnwrapLeft.EmitCheck(ec); ec.Emit(OpCodes.Brfalse_S, load_right); // load left ec.MarkLabel(load_left); if (or) { UnwrapRight.Load(ec); } else { UnwrapLeft.Load(ec); } ec.Emit(OpCodes.Br_S, end_label); // load right ec.MarkLabel(load_right); if (or) { UnwrapLeft.Load(ec); } else { UnwrapRight.Load(ec); } ec.MarkLabel(end_label); return; } // // Faster version when one operand is bool // if (UnwrapLeft == null) { // // (bool, bool?) // // Optimizes remaining (false & bool?), (true | bool?) which are not easy to handle // in binary expression reduction // var c = Left as BoolConstant; if (c != null) { // Keep evaluation order UnwrapRight.Store(ec); ec.EmitInt(or ? 1 : 0); ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); } else if (Left.IsNull) { UnwrapRight.Emit(ec); ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label); UnwrapRight.Load(ec); ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(is_null_label); LiftedNull.Create(type, loc).Emit(ec); } else { Left.Emit(ec); UnwrapRight.Store(ec); ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_right); ec.EmitInt(or ? 1 : 0); ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(load_right); UnwrapRight.Load(ec); } } else { // // (bool?, bool) // // Keep left-right evaluation order UnwrapLeft.Store(ec); // // Optimizes remaining (bool? & false), (bool? | true) which are not easy to handle // in binary expression reduction // var c = Right as BoolConstant; if (c != null) { ec.EmitInt(or ? 1 : 0); ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); } else if (Right.IsNull) { UnwrapLeft.Emit(ec); ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label); UnwrapLeft.Load(ec); ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(is_null_label); LiftedNull.Create(type, loc).Emit(ec); } else if (Left.IsNull && UnwrapRight != null) { UnwrapRight.Emit(ec); ec.Emit(or ? OpCodes.Brtrue_S : OpCodes.Brfalse_S, load_right); LiftedNull.Create(type, loc).Emit(ec); ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(load_right); UnwrapRight.Load(ec); } else { Right.Emit(ec); ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_left); ec.EmitInt(or ? 1 : 0); ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(load_left); UnwrapLeft.Load(ec); } } ec.MarkLabel(end_label); }
public override void Emit(EmitContext ec) { if (IsBitwiseBoolean && UserOperator == null) { EmitBitwiseBoolean(ec); return; } if ((Binary.Oper & Binary.Operator.EqualityMask) != 0) { EmitEquality(ec); return; } Label is_null_label = ec.DefineLabel(); Label end_label = ec.DefineLabel(); if (ec.HasSet(BuilderContext.Options.AsyncBody) && Right.ContainsEmitWithAwait()) { Left = Left.EmitToField(ec); Right = Right.EmitToField(ec); } if (UnwrapLeft != null) { UnwrapLeft.EmitCheck(ec); } // // Don't emit HasValue check when left and right expressions are same // if (UnwrapRight != null && !Binary.Left.Equals(Binary.Right)) { UnwrapRight.EmitCheck(ec); if (UnwrapLeft != null) { ec.Emit(OpCodes.And); } } ec.Emit(OpCodes.Brfalse, is_null_label); if (UserOperator != null) { var args = new Arguments(2); args.Add(new Argument(Left)); args.Add(new Argument(Right)); var call = new CallEmitter(); call.EmitPredefined(ec, UserOperator, args); } else { Binary.EmitOperator(ec, Left, Right); } // // Wrap the result when the operator return type is nullable type // if (type.IsNullableType) { ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); } ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(is_null_label); if ((Binary.Oper & Binary.Operator.ComparisonMask) != 0) { ec.EmitInt(0); } else { LiftedNull.Create(type, loc).Emit(ec); } ec.MarkLabel(end_label); }
public override void Emit(EmitContext ec) { Label end_label = ec.DefineLabel(); if (unwrap != null) { Label is_null_label = ec.DefineLabel(); unwrap.EmitCheck(ec); ec.Emit(OpCodes.Brfalse, is_null_label); // // When both expressions are nullable the unwrap // is needed only for null check not for value uwrap // if (type.IsNullableType && TypeSpecComparer.IsEqual(NullableInfo.GetUnderlyingType(type), unwrap.Type)) { unwrap.Load(ec); } else { left.Emit(ec); } ec.Emit(OpCodes.Br, end_label); ec.MarkLabel(is_null_label); right.Emit(ec); ec.MarkLabel(end_label); return; } // // Null check is done on original expression not after expression is converted to // result type. This is in most cases same but when user conversion is involved // we can end up in situation when user operator does the null handling which is // not what the operator is supposed to do. // There is tricky case where cast of left expression is meant to be cast of // whole source expression (null check is done on it) and cast from right-to-left // conversion needs to do null check on unconverted source expression. // if (user_conversion_left) { var op_expr = (UserCast)left; op_expr.Source.Emit(ec); LocalTemporary temp; // TODO: More load kinds can be special cased if (!(op_expr.Source is VariableReference)) { temp = new LocalTemporary(op_expr.Source.Type); temp.Store(ec); temp.Emit(ec); op_expr.Source = temp; } else { temp = null; } var right_label = ec.DefineLabel(); ec.Emit(OpCodes.Brfalse_S, right_label); left.Emit(ec); ec.Emit(OpCodes.Br, end_label); ec.MarkLabel(right_label); if (temp != null) { temp.Release(ec); } } else { // // Common case where expression is not modified before null check and // we generate better/smaller code // left.Emit(ec); ec.Emit(OpCodes.Dup); // Only to make verifier happy if (left.Type.IsGenericParameter) { ec.Emit(OpCodes.Box, left.Type); } ec.Emit(OpCodes.Brtrue, end_label); ec.Emit(OpCodes.Pop); } right.Emit(ec); ec.MarkLabel(end_label); }
public override void Emit (EmitContext ec) { child.Emit (ec); ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); }
public void AddressOf (EmitContext ec, AddressOp Mode) { LocalTemporary value_target = new LocalTemporary (type); value_target.AddressOf (ec, AddressOp.Store); ec.Emit (OpCodes.Initobj, type); ((IMemoryLocation) value_target).AddressOf (ec, Mode); }
public override void Emit(EmitContext ec) { // // Optimize same expression operation // if (right_unwrap != null && right.Equals(left)) { right_unwrap = left_unwrap; } if (user_operator == null && IsBitwiseBoolean) { EmitBitwiseBoolean(ec); return; } if ((Oper & Operator.EqualityMask) != 0) { EmitEquality(ec); return; } Label is_null_label = ec.DefineLabel(); Label end_label = ec.DefineLabel(); if (left_unwrap != null) { left_unwrap.EmitCheck(ec); ec.Emit(OpCodes.Brfalse, is_null_label); } // // Don't emit HasValue check when left and right expressions are same // if (right_unwrap != null && !left.Equals(right)) { right_unwrap.EmitCheck(ec); ec.Emit(OpCodes.Brfalse, is_null_label); } EmitOperator(ec, left.Type); if (wrap_ctor != null) { ec.Emit(OpCodes.Newobj, wrap_ctor); } ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(is_null_label); if ((Oper & Operator.ComparisonMask) != 0) { ec.Emit(OpCodes.Ldc_I4_0); } else { LiftedNull.Create(type, loc).Emit(ec); } ec.MarkLabel(end_label); }
public override void EmitBranchable (EmitContext ec, Label target, bool onTrue) { Emit (ec); ec.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target); }
private void EmitNonLiftedBinary(EmitContext emitContext) { emitContext.Emit(_left); emitContext.Emit(_right); EmitBinaryOperator(emitContext); }
void EmitUserDefinedLogicalShortCircuit (EmitContext ec) { var ig = ec.ig; var and = NodeType == ExpressionType.AndAlso; var done = ig.DefineLabel (); var left = ec.EmitStored (this.left); ec.EmitLoad (left); ig.Emit (OpCodes.Dup); ec.EmitCall (and ? GetFalseOperator () : GetTrueOperator ()); ig.Emit (OpCodes.Brtrue, done); ec.Emit (this.right); ec.EmitCall (method); ig.MarkLabel (done); }
public override void Emit (EmitContext ec) { Label end_label = ec.DefineLabel (); if (unwrap != null) { Label is_null_label = ec.DefineLabel (); unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse, is_null_label); // // When both expressions are nullable the unwrap // is needed only for null check not for value uwrap // if (type.IsNullableType) unwrap.Load (ec); else left.Emit (ec); ec.Emit (OpCodes.Br, end_label); ec.MarkLabel (is_null_label); right.Emit (ec); ec.MarkLabel (end_label); return; } left.Emit (ec); ec.Emit (OpCodes.Dup); // Only to make verifier happy if (left.Type.IsGenericParameter) ec.Emit (OpCodes.Box, left.Type); ec.Emit (OpCodes.Brtrue, end_label); ec.Emit (OpCodes.Pop); right.Emit (ec); ec.MarkLabel (end_label); }
void EmitConvertedCoalesce (EmitContext ec) { var ig = ec.ig; var done = ig.DefineLabel (); var load_right = ig.DefineLabel (); var left = ec.EmitStored (this.left); if (left.LocalType.IsNullable ()) ec.EmitNullableHasValue (left); else ec.EmitLoad (left); ig.Emit (OpCodes.Brfalse, load_right); ec.Emit (conversion); ec.EmitLoad (left); ig.Emit (OpCodes.Callvirt, conversion.Type.GetInvokeMethod ()); ig.Emit (OpCodes.Br, done); ig.MarkLabel (load_right); ec.Emit (this.right); ig.MarkLabel (done); }
public override void Emit (EmitContext ec) { Label end_label = ec.DefineLabel (); if (unwrap != null) { Label is_null_label = ec.DefineLabel (); unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse, is_null_label); // // When both expressions are nullable the unwrap // is needed only for null check not for value uwrap // if (type.IsNullableType && TypeSpecComparer.IsEqual (NullableInfo.GetUnderlyingType (type), unwrap.Type)) unwrap.Load (ec); else left.Emit (ec); ec.Emit (OpCodes.Br, end_label); ec.MarkLabel (is_null_label); right.Emit (ec); ec.MarkLabel (end_label); return; } // // Null check is done on original expression not after expression is converted to // result type. This is in most cases same but when user conversion is involved // we can end up in situation when user operator does the null handling which is // not what the operator is supposed to do. // There is tricky case where cast of left expression is meant to be cast of // whole source expression (null check is done on it) and cast from right-to-left // conversion needs to do null check on unconverted source expression. // if (user_conversion_left) { var op_expr = (UserCast) left; op_expr.Source.Emit (ec); LocalTemporary temp; // TODO: More load kinds can be special cased if (!(op_expr.Source is VariableReference)) { temp = new LocalTemporary (op_expr.Source.Type); temp.Store (ec); temp.Emit (ec); op_expr.Source = temp; } else { temp = null; } var right_label = ec.DefineLabel (); ec.Emit (OpCodes.Brfalse_S, right_label); left.Emit (ec); ec.Emit (OpCodes.Br, end_label); ec.MarkLabel (right_label); if (temp != null) temp.Release (ec); } else { // // Common case where expression is not modified before null check and // we generate better/smaller code // left.Emit (ec); ec.Emit (OpCodes.Dup); // Only to make verifier happy if (left.Type.IsGenericParameter) ec.Emit (OpCodes.Box, left.Type); ec.Emit (OpCodes.Brtrue, end_label); ec.Emit (OpCodes.Pop); } right.Emit (ec); ec.MarkLabel (end_label); }
void EmitNonLiftedBinary (EmitContext ec) { ec.Emit (left); ec.Emit (right); EmitBinaryOperator (ec); }
public override void Emit(EmitContext ec) { Label end_label = ec.DefineLabel (); if (unwrap != null) { Label is_null_label = ec.DefineLabel (); unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse, is_null_label); left.Emit (ec); ec.Emit (OpCodes.Br, end_label); ec.MarkLabel (is_null_label); right.Emit (ec); ec.MarkLabel (end_label); return; } left.Emit (ec); ec.Emit (OpCodes.Dup); ec.Emit (OpCodes.Brtrue, end_label); ec.Emit (OpCodes.Pop); right.Emit (ec); ec.MarkLabel (end_label); }
public override void Emit (EmitContext ec) { if (IsBitwiseBoolean && UserOperator == null) { EmitBitwiseBoolean (ec); return; } if ((Binary.Oper & Binary.Operator.EqualityMask) != 0) { EmitEquality (ec); return; } Label is_null_label = ec.DefineLabel (); Label end_label = ec.DefineLabel (); if (ec.HasSet (BuilderContext.Options.AsyncBody) && Right.ContainsEmitWithAwait ()) { Left = Left.EmitToField (ec); Right = Right.EmitToField (ec); } if (UnwrapLeft != null) { UnwrapLeft.EmitCheck (ec); } // // Don't emit HasValue check when left and right expressions are same // if (UnwrapRight != null && !Binary.Left.Equals (Binary.Right)) { UnwrapRight.EmitCheck (ec); if (UnwrapLeft != null) { ec.Emit (OpCodes.And); } } ec.Emit (OpCodes.Brfalse, is_null_label); if (UserOperator != null) { var args = new Arguments (2); args.Add (new Argument (Left)); args.Add (new Argument (Right)); var call = new CallEmitter (); call.EmitPredefined (ec, UserOperator, args); } else { Binary.EmitOperator (ec, Left, Right); } // // Wrap the result when the operator return type is nullable type // if (type.IsNullableType) ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); ec.Emit (OpCodes.Br_S, end_label); ec.MarkLabel (is_null_label); if ((Binary.Oper & Binary.Operator.ComparisonMask) != 0) { ec.EmitInt (0); } else { LiftedNull.Create (type, loc).Emit (ec); } ec.MarkLabel (end_label); }
// // Emits optimized equality or inequality operator when possible // void EmitEquality (EmitContext ec) { // // Either left or right is null // if (left_unwrap != null && (IsRightNullLifted || right.IsNull)) { left_unwrap.EmitCheck (ec); if (Oper == Binary.Operator.Equality) { ec.EmitInt (0); ec.Emit (OpCodes.Ceq); } return; } if (right_unwrap != null && (IsLeftNullLifted || left.IsNull)) { right_unwrap.EmitCheck (ec); if (Oper == Binary.Operator.Equality) { ec.EmitInt (0); ec.Emit (OpCodes.Ceq); } return; } Label dissimilar_label = ec.DefineLabel (); Label end_label = ec.DefineLabel (); if (user_operator != null) { user_operator.Emit (ec); ec.Emit (Oper == Operator.Equality ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, dissimilar_label); } else { if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) { left = left.EmitToField (ec); right = right.EmitToField (ec); } left.Emit (ec); right.Emit (ec); ec.Emit (OpCodes.Bne_Un_S, dissimilar_label); } if (left_unwrap != null) left_unwrap.EmitCheck (ec); if (right_unwrap != null) right_unwrap.EmitCheck (ec); if (left_unwrap != null && right_unwrap != null) { if (Oper == Operator.Inequality) ec.Emit (OpCodes.Xor); else ec.Emit (OpCodes.Ceq); } else { if (Oper == Operator.Inequality) { ec.EmitInt (0); ec.Emit (OpCodes.Ceq); } } ec.Emit (OpCodes.Br_S, end_label); ec.MarkLabel (dissimilar_label); if (Oper == Operator.Inequality) ec.EmitInt (1); else ec.EmitInt (0); ec.MarkLabel (end_label); }
// // Emits optimized equality or inequality operator when possible // void EmitEquality (EmitContext ec) { // // Either left or right is null // if (UnwrapLeft != null && Binary.Right.IsNull) { // TODO: Optimize for EmitBranchable // // left.HasValue == false // UnwrapLeft.EmitCheck (ec); if (Binary.Oper == Binary.Operator.Equality) { ec.EmitInt (0); ec.Emit (OpCodes.Ceq); } return; } if (UnwrapRight != null && Binary.Left.IsNull) { // // right.HasValue == false // UnwrapRight.EmitCheck (ec); if (Binary.Oper == Binary.Operator.Equality) { ec.EmitInt (0); ec.Emit (OpCodes.Ceq); } return; } Label dissimilar_label = ec.DefineLabel (); Label end_label = ec.DefineLabel (); if (UserOperator != null) { var left = Left; if (UnwrapLeft != null) { UnwrapLeft.EmitCheck (ec); } else { // Keep evaluation order same if (!(Left is VariableReference)) { Left.Emit (ec); var lt = new LocalTemporary (Left.Type); lt.Store (ec); left = lt; } } if (UnwrapRight != null) { UnwrapRight.EmitCheck (ec); if (UnwrapLeft != null) { ec.Emit (OpCodes.Bne_Un, dissimilar_label); Label compare_label = ec.DefineLabel (); UnwrapLeft.EmitCheck (ec); ec.Emit (OpCodes.Brtrue, compare_label); if (Binary.Oper == Binary.Operator.Equality) ec.EmitInt (1); else ec.EmitInt (0); ec.Emit (OpCodes.Br, end_label); ec.MarkLabel (compare_label); } else { ec.Emit (OpCodes.Brfalse, dissimilar_label); } } else { ec.Emit (OpCodes.Brfalse, dissimilar_label); } var args = new Arguments (2); args.Add (new Argument (left)); args.Add (new Argument (Right)); var call = new CallEmitter (); call.EmitPredefined (ec, UserOperator, args); } else { if (ec.HasSet (BuilderContext.Options.AsyncBody) && Binary.Right.ContainsEmitWithAwait ()) { Left = Left.EmitToField (ec); Right = Right.EmitToField (ec); } // // Emit underlying value comparison first. // // For this code: int? a = 1; bool b = a == 1; // // We emit something similar to this. Expressions with side effects have local // variable created by Unwrap expression // // left.GetValueOrDefault () // right // bne.un.s dissimilar_label // left.HasValue // br.s end_label // dissimilar_label: // ldc.i4.0 // end_label: // Left.Emit (ec); Right.Emit (ec); ec.Emit (OpCodes.Bne_Un_S, dissimilar_label); // // Check both left and right expressions for Unwrap call in which // case we need to run get_HasValue() check because the type is // nullable and could have null value // if (UnwrapLeft != null) UnwrapLeft.EmitCheck (ec); if (UnwrapRight != null) UnwrapRight.EmitCheck (ec); if (UnwrapLeft != null && UnwrapRight != null) { if (Binary.Oper == Binary.Operator.Inequality) ec.Emit (OpCodes.Xor); else ec.Emit (OpCodes.Ceq); } else { if (Binary.Oper == Binary.Operator.Inequality) { ec.EmitInt (0); ec.Emit (OpCodes.Ceq); } } } ec.Emit (OpCodes.Br_S, end_label); ec.MarkLabel (dissimilar_label); if (Binary.Oper == Binary.Operator.Inequality) ec.EmitInt (1); else ec.EmitInt (0); ec.MarkLabel (end_label); }
void EmitBitwiseBoolean (EmitContext ec) { Label load_left = ec.DefineLabel (); Label load_right = ec.DefineLabel (); Label end_label = ec.DefineLabel (); left_unwrap.Emit (ec); ec.Emit (OpCodes.Brtrue_S, load_right); right_unwrap.Emit (ec); ec.Emit (OpCodes.Brtrue_S, load_left); left_unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse_S, load_right); // load left ec.MarkLabel (load_left); if (Oper == Operator.BitwiseAnd) { left_unwrap.Load (ec); } else { right_unwrap.Load (ec); right_unwrap = left_unwrap; } ec.Emit (OpCodes.Br_S, end_label); // load right ec.MarkLabel (load_right); right_unwrap.Load (ec); ec.MarkLabel (end_label); }
void DoEmit (EmitContext ec, bool is_expr) { Label is_null_label = ec.DefineLabel (); Label end_label = ec.DefineLabel (); unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse, is_null_label); if (is_expr) { underlying.Emit (ec); ec.Emit (OpCodes.Br_S, end_label); } else { underlying.EmitStatement (ec); } ec.MarkLabel (is_null_label); if (is_expr) LiftedNull.Create (type, loc).Emit (ec); ec.MarkLabel (end_label); }
void EmitConvertToNullable (EmitContext ec) { ec.Emit (operand); if (IsUnBoxing ()) { EmitUnbox (ec); return; } if (operand.Type != Type.GetNotNullableType ()) { EmitPrimitiveConversion (ec, operand.Type, Type.GetNotNullableType ()); } ec.EmitNullableNew (Type); }
public override void Emit (EmitContext ec) { // TODO: generate less temporary variables LocalTemporary value_target = new LocalTemporary (type); value_target.AddressOf (ec, AddressOp.Store); ec.Emit (OpCodes.Initobj, type); value_target.Emit (ec); }
void EmitConvertFromNullable (EmitContext ec) { if (IsBoxing ()) { ec.Emit (operand); EmitBox (ec); return; } ec.EmitCall (operand, operand.Type.GetMethod ("get_Value")); if (operand.Type.GetNotNullableType () != Type) { EmitPrimitiveConversion (ec, operand.Type.GetNotNullableType (), Type); } }
public override void Emit (EmitContext ec) { Label is_null_label = ec.DefineLabel (); Label end_label = ec.DefineLabel (); unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse, is_null_label); if (user_operator != null) { user_operator.Emit (ec); } else { EmitOperator (ec, NullableInfo.GetUnderlyingType (type)); } ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); ec.Emit (OpCodes.Br_S, end_label); ec.MarkLabel (is_null_label); LiftedNull.Create (type, loc).Emit (ec); ec.MarkLabel (end_label); }
void EmitUserDefinedOperator (EmitContext ec) { if (!IsLifted) { ec.Emit (operand); ec.EmitCall (method); } else if (IsLiftedToNull) { EmitUserDefinedLiftedToNullOperator (ec); } else EmitUserDefinedLiftedOperator (ec); }
// // Emits optimized equality or inequality operator when possible // void EmitEquality (EmitContext ec) { // // Either left or right is null // if (left_unwrap != null && (IsRightNullLifted || right.IsNull)) { left_unwrap.EmitCheck (ec); if (Oper == Binary.Operator.Equality) { ec.Emit (OpCodes.Ldc_I4_0); ec.Emit (OpCodes.Ceq); } return; } if (right_unwrap != null && (IsLeftNullLifted || left.IsNull)) { right_unwrap.EmitCheck (ec); if (Oper == Binary.Operator.Equality) { ec.Emit (OpCodes.Ldc_I4_0); ec.Emit (OpCodes.Ceq); } return; } Label dissimilar_label = ec.DefineLabel (); Label end_label = ec.DefineLabel (); if (user_operator != null) { user_operator.Emit (ec); ec.Emit (Oper == Operator.Equality ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, dissimilar_label); } else { left.Emit (ec); right.Emit (ec); ec.Emit (OpCodes.Bne_Un_S, dissimilar_label); } if (left_unwrap != null) left_unwrap.EmitCheck (ec); if (right_unwrap != null) right_unwrap.EmitCheck (ec); if (left_unwrap != null && right_unwrap != null) { if (Oper == Operator.Inequality) ec.Emit (OpCodes.Xor); else ec.Emit (OpCodes.Ceq); } else { if (Oper == Operator.Inequality) { ec.Emit (OpCodes.Ldc_I4_0); ec.Emit (OpCodes.Ceq); } } ec.Emit (OpCodes.Br_S, end_label); ec.MarkLabel (dissimilar_label); if (Oper == Operator.Inequality) ec.Emit (OpCodes.Ldc_I4_1); else ec.Emit (OpCodes.Ldc_I4_0); ec.MarkLabel (end_label); }
void EmitLogicalShortCircuit (EmitContext ec) { var ig = ec.ig; var and = NodeType == ExpressionType.AndAlso; var ret = ig.DefineLabel (); var done = ig.DefineLabel (); ec.Emit (left); ig.Emit (and ? OpCodes.Brfalse : OpCodes.Brtrue, ret); ec.Emit (right); ig.Emit (OpCodes.Br, done); ig.MarkLabel (ret); ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1); ig.MarkLabel (done); }
public override void Emit (EmitContext ec) { // // Optimize same expression operation // if (right_unwrap != null && right.Equals (left)) right_unwrap = left_unwrap; if (user_operator == null && IsBitwiseBoolean) { EmitBitwiseBoolean (ec); return; } if ((Oper & Operator.EqualityMask) != 0) { EmitEquality (ec); return; } Label is_null_label = ec.DefineLabel (); Label end_label = ec.DefineLabel (); if (left_unwrap != null) { left_unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse, is_null_label); } // // Don't emit HasValue check when left and right expressions are same // if (right_unwrap != null && !left.Equals (right)) { right_unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse, is_null_label); } EmitOperator (ec, left.Type); if (wrap_ctor != null) ec.Emit (OpCodes.Newobj, wrap_ctor); ec.Emit (OpCodes.Br_S, end_label); ec.MarkLabel (is_null_label); if ((Oper & Operator.ComparisonMask) != 0) { ec.Emit (OpCodes.Ldc_I4_0); } else { LiftedNull.Create (type, loc).Emit (ec); } ec.MarkLabel (end_label); }
protected override void DoEmit(EmitContext ec) { var variable = ec.ResolveVariable(this, null); if (variable != null) { if (variable.Scope == VariableScope.Function) { ec.Emit(OpCode.LoadConstant, Value.Pointer(variable.Address)); } else { if (variable.VariableType is CBasicType || variable.VariableType is CPointerType || variable.VariableType is CEnumType) { if (variable.Scope == VariableScope.Arg) { ec.Emit(OpCode.LoadArg, variable.Address); } else if (variable.Scope == VariableScope.Global) { ec.Emit(OpCode.LoadGlobal, variable.Address); } else if (variable.Scope == VariableScope.Local) { ec.Emit(OpCode.LoadLocal, variable.Address); } else if (variable.Scope == VariableScope.Constant) { ec.Emit(OpCode.LoadConstant, variable.Constant); } else { throw new NotSupportedException("Cannot evaluate variable scope '" + variable.Scope + "'"); } } else if (variable.VariableType is CArrayType arrayType) { if (variable.Scope == VariableScope.Arg) { ec.Emit(OpCode.LoadConstant, Value.Pointer(variable.Address)); ec.Emit(OpCode.LoadFramePointer); ec.Emit(OpCode.OffsetPointer); } else if (variable.Scope == VariableScope.Global) { ec.Emit(OpCode.LoadConstant, Value.Pointer(variable.Address)); } else if (variable.Scope == VariableScope.Local) { ec.Emit(OpCode.LoadConstant, Value.Pointer(variable.Address)); ec.Emit(OpCode.LoadFramePointer); ec.Emit(OpCode.OffsetPointer); } else { throw new NotSupportedException("Cannot evaluate array variable scope '" + variable.Scope + "'"); } } else { throw new NotSupportedException("Cannot evaluate variable type '" + variable.VariableType + "'"); } } } else { ec.Emit(OpCode.LoadConstant, 0); } }