public void AddressOf(EmitContext ec, AddressOp mode) { IMemoryLocation ml; if (temp_field != null) { ml = temp_field as IMemoryLocation; if (ml == null) { var lt = new LocalTemporary(temp_field.Type); temp_field.Emit(ec); lt.Store(ec); ml = lt; } } else { ml = expr as VariableReference; } if (ml != null) { ml.AddressOf(ec, mode); } else { LocalVariable.AddressOf(ec, mode); } }
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); }
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 use operator does the null handling which is // not what the operator is supposed to do // var op_expr = left as UserCast; if (op_expr != null) { 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); }
// // 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); }
// // 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); }
public void AddressOf (EmitContext ec, AddressOp mode) { IMemoryLocation ml; if (temp_field != null) { ml = temp_field as IMemoryLocation; if (ml == null) { var lt = new LocalTemporary (temp_field.Type); temp_field.Emit (ec); lt.Store (ec); ml = lt; } } else { ml = expr as VariableReference; } if (ml != null) ml.AddressOf (ec, mode); else LocalVariable.AddressOf (ec, mode); }
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); }
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); }