this.is_lifted = is_lifted;
}
- void EmitMethod (EmitContext ec)
- {
- left.Emit (ec);
- right.Emit (ec);
- ec.EmitCall (method);
- }
-
+#if !FULL_AOT_RUNTIME
void EmitArrayAccess (EmitContext ec)
{
left.Emit (ec);
ig.MarkLabel (done);
}
+ MethodInfo GetFalseOperator ()
+ {
+ return GetFalseOperator (left.Type.GetNotNullableType ());
+ }
+
+ MethodInfo GetTrueOperator ()
+ {
+ return GetTrueOperator (left.Type.GetNotNullableType ());
+ }
+
+ 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);
+ }
+
void EmitLiftedLogicalShortCircuit (EmitContext ec)
{
var ig = ec.ig;
ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
ig.MarkLabel (ret_new);
- ec.EmitNullableNew (typeof (bool?));
+ ec.EmitNullableNew (Type);
ig.Emit (OpCodes.Br, done);
ig.MarkLabel (ret_null);
- var ret = ig.DeclareLocal (typeof (bool?));
+ var ret = ig.DeclareLocal (Type);
ec.EmitNullableInitialize (ret);
ig.MarkLabel (done);
void EmitCoalesce (EmitContext ec)
{
- ILGenerator ig = ec.ig;
+ 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);
- LocalBuilder vleft;
- LocalBuilder vright;
+ ig.MarkLabel (done);
+ }
- MethodInfo has_value = left.Type.GetMethod ("get_HasValue");
+ void EmitConvertedCoalesce (EmitContext ec)
+ {
+ var ig = ec.ig;
+ var done = ig.DefineLabel ();
+ var load_right = ig.DefineLabel ();
- Label exit = ig.DefineLabel ();
- Label try_right = ig.DefineLabel ();
- Label setup_null = ig.DefineLabel ();
+ var left = ec.EmitStored (this.left);
- vleft = ec.EmitStored (left);
- if (IsNullable (left.Type)){
- ig.Emit (OpCodes.Ldloca, vleft);
- ig.Emit (OpCodes.Call, has_value);
- } else
- ig.Emit (OpCodes.Ldloc, vleft);
+ if (left.LocalType.IsNullable ())
+ ec.EmitNullableHasValue (left);
+ else
+ ec.EmitLoad (left);
- ig.Emit (OpCodes.Brfalse, try_right);
- ig.Emit (OpCodes.Ldloc, vleft);
- ig.Emit (OpCodes.Br, exit);
+ ig.Emit (OpCodes.Brfalse, load_right);
- // try_right;
- ig.MarkLabel (try_right);
- vright = ec.EmitStored (right);
- if (IsNullable (right.Type)){
- ig.Emit (OpCodes.Ldloca, vright);
- ig.Emit (OpCodes.Call, has_value);
- } else
- ig.Emit (OpCodes.Ldloc, vright);
+ ec.Emit (conversion);
+ ec.EmitLoad (left);
+ ig.Emit (OpCodes.Callvirt, conversion.Type.GetInvokeMethod ());
- ig.Emit (OpCodes.Brfalse, setup_null);
- ig.Emit (OpCodes.Ldloc, vright);
- ig.Emit (OpCodes.Br, exit);
+ ig.Emit (OpCodes.Br, done);
- // setup_null:
- ig.MarkLabel (setup_null);
- LocalBuilder ret = ig.DeclareLocal (Type);
- ig.Emit (OpCodes.Ldloca, ret);
- ig.Emit (OpCodes.Initobj, Type);
- ig.Emit (OpCodes.Ldloc, ret);
+ ig.MarkLabel (load_right);
+ ec.Emit (this.right);
- // exit:
- ig.MarkLabel (exit);
+ ig.MarkLabel (done);
+ }
+
+ static bool IsInt32OrInt64 (Type type)
+ {
+ return type == typeof (int) || type == typeof (long);
+ }
+
+ static bool IsSingleOrDouble (Type type)
+ {
+ return type == typeof (float) || type == typeof (double);
}
void EmitBinaryOperator (EmitContext ec)
{
- OpCode opcode;
var ig = ec.ig;
bool is_unsigned = IsUnsigned (left.Type);
switch (NodeType) {
case ExpressionType.Add:
- opcode = OpCodes.Add;
+ ig.Emit (OpCodes.Add);
break;
case ExpressionType.AddChecked:
- if (left.Type == typeof (int) || left.Type == typeof (long))
- opcode = OpCodes.Add_Ovf;
+ if (IsInt32OrInt64 (left.Type))
+ ig.Emit (OpCodes.Add_Ovf);
else
- opcode = is_unsigned ? OpCodes.Add_Ovf_Un : OpCodes.Add;
+ ig.Emit (is_unsigned ? OpCodes.Add_Ovf_Un : OpCodes.Add);
break;
case ExpressionType.Subtract:
- opcode = OpCodes.Sub;
+ ig.Emit (OpCodes.Sub);
break;
case ExpressionType.SubtractChecked:
- if (left.Type == typeof (int) || left.Type == typeof (long))
- opcode = OpCodes.Sub_Ovf;
+ if (IsInt32OrInt64 (left.Type))
+ ig.Emit (OpCodes.Sub_Ovf);
else
- opcode = is_unsigned ? OpCodes.Sub_Ovf_Un : OpCodes.Sub;
+ ig.Emit (is_unsigned ? OpCodes.Sub_Ovf_Un : OpCodes.Sub);
break;
case ExpressionType.Multiply:
- opcode = OpCodes.Mul;
+ ig.Emit (OpCodes.Mul);
break;
case ExpressionType.MultiplyChecked:
- if (left.Type == typeof (int) || left.Type == typeof (long))
- opcode = OpCodes.Mul_Ovf;
+ if (IsInt32OrInt64 (left.Type))
+ ig.Emit (OpCodes.Mul_Ovf);
else
- opcode = is_unsigned ? OpCodes.Mul_Ovf_Un : OpCodes.Mul;
+ ig.Emit (is_unsigned ? OpCodes.Mul_Ovf_Un : OpCodes.Mul);
break;
case ExpressionType.Divide:
- opcode = is_unsigned ? OpCodes.Div_Un : OpCodes.Div;
+ ig.Emit (is_unsigned ? OpCodes.Div_Un : OpCodes.Div);
break;
case ExpressionType.Modulo:
- opcode = is_unsigned ? OpCodes.Rem_Un : OpCodes.Rem;
+ ig.Emit (is_unsigned ? OpCodes.Rem_Un : OpCodes.Rem);
break;
case ExpressionType.RightShift:
- opcode = is_unsigned ? OpCodes.Shr_Un : OpCodes.Shr;
- break;
case ExpressionType.LeftShift:
- opcode = OpCodes.Shl;
+ ig.Emit (OpCodes.Ldc_I4, left.Type == typeof (int) ? 0x1f : 0x3f);
+ ig.Emit (OpCodes.And);
+ if (NodeType == ExpressionType.RightShift)
+ ig.Emit (is_unsigned ? OpCodes.Shr_Un : OpCodes.Shr);
+ else
+ ig.Emit (OpCodes.Shl);
break;
case ExpressionType.And:
- opcode = OpCodes.And;
+ ig.Emit (OpCodes.And);
break;
case ExpressionType.Or:
- opcode = OpCodes.Or;
+ ig.Emit (OpCodes.Or);
break;
case ExpressionType.ExclusiveOr:
- opcode = OpCodes.Xor;
+ ig.Emit (OpCodes.Xor);
break;
case ExpressionType.GreaterThan:
- opcode = is_unsigned ? OpCodes.Cgt_Un : OpCodes.Cgt;
+ ig.Emit (is_unsigned ? OpCodes.Cgt_Un : OpCodes.Cgt);
break;
case ExpressionType.GreaterThanOrEqual:
- Type le = left.Type;
-
- if (is_unsigned || (le == typeof (double) || le == typeof (float)))
+ if (is_unsigned || IsSingleOrDouble (left.Type))
ig.Emit (OpCodes.Clt_Un);
else
ig.Emit (OpCodes.Clt);
ig.Emit (OpCodes.Ldc_I4_0);
-
- opcode = OpCodes.Ceq;
+ ig.Emit (OpCodes.Ceq);
break;
case ExpressionType.LessThan:
- opcode = is_unsigned ? OpCodes.Clt_Un : OpCodes.Clt;
+ ig.Emit (is_unsigned ? OpCodes.Clt_Un : OpCodes.Clt);
break;
case ExpressionType.LessThanOrEqual:
- Type lt = left.Type;
-
- if (is_unsigned || (lt == typeof (double) || lt == typeof (float)))
+ if (is_unsigned || IsSingleOrDouble (left.Type))
ig.Emit (OpCodes.Cgt_Un);
else
ig.Emit (OpCodes.Cgt);
ig.Emit (OpCodes.Ldc_I4_0);
-
- opcode = OpCodes.Ceq;
+ ig.Emit (OpCodes.Ceq);
break;
case ExpressionType.Equal:
- opcode = OpCodes.Ceq;
+ ig.Emit (OpCodes.Ceq);
break;
case ExpressionType.NotEqual:
ig.Emit (OpCodes.Ceq);
ig.Emit (OpCodes.Ldc_I4_0);
- opcode = OpCodes.Ceq;
+ ig.Emit (OpCodes.Ceq);
+ break;
+ case ExpressionType.Power:
+ ig.Emit (OpCodes.Call, typeof (Math).GetMethod ("Pow"));
break;
default:
- throw new InvalidOperationException (string.Format ("Internal error: BinaryExpression contains non-Binary nodetype {0}", NodeType));
+ throw new InvalidOperationException (
+ string.Format ("Internal error: BinaryExpression contains non-Binary nodetype {0}", NodeType));
}
+ }
- ig.Emit (opcode);
+ bool IsLeftLiftedBinary ()
+ {
+ return left.Type.IsNullable () && !right.Type.IsNullable ();
+ }
+
+ 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 EmitLiftedArithmeticBinary (EmitContext ec)
{
- EmitLiftedToNullBinary (ec);
+ if (IsLeftLiftedBinary ())
+ EmitLeftLiftedToNullBinary (ec);
+ else
+ EmitLiftedToNullBinary (ec);
}
void EmitLiftedToNullBinary (EmitContext ec)
EmitLiftedRelationalBinary (ec);
}
+ void EmitLiftedUserDefinedOperator (EmitContext ec)
+ {
+ var ig = ec.ig;
+
+ var ret_true = ig.DefineLabel ();
+ var ret_false = ig.DefineLabel ();
+ var done = ig.DefineLabel ();
+
+ var left = ec.EmitStored (this.left);
+ var right = ec.EmitStored (this.right);
+
+ ec.EmitNullableHasValue (left);
+ ec.EmitNullableHasValue (right);
+ switch (NodeType) {
+ case ExpressionType.Equal:
+ ig.Emit (OpCodes.Bne_Un, ret_false);
+ ec.EmitNullableHasValue (left);
+ ig.Emit (OpCodes.Brfalse, ret_true);
+ break;
+ case ExpressionType.NotEqual:
+ ig.Emit (OpCodes.Bne_Un, ret_true);
+ ec.EmitNullableHasValue (left);
+ ig.Emit (OpCodes.Brfalse, ret_false);
+ break;
+ default:
+ ig.Emit (OpCodes.And);
+ ig.Emit (OpCodes.Brfalse, ret_false);
+ break;
+ }
+
+ ec.EmitNullableGetValueOrDefault (left);
+ ec.EmitNullableGetValueOrDefault (right);
+ ec.EmitCall (method);
+ ig.Emit (OpCodes.Br, done);
+
+ ig.MarkLabel (ret_true);
+ ig.Emit (OpCodes.Ldc_I4_1);
+ ig.Emit (OpCodes.Br, done);
+
+ ig.MarkLabel (ret_false);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Br, done);
+
+ ig.MarkLabel (done);
+ }
+
+ void EmitLiftedToNullUserDefinedOperator (EmitContext ec)
+ {
+ var ig = ec.ig;
+
+ var ret = ig.DefineLabel ();
+ var done = ig.DefineLabel ();
+
+ var left = ec.EmitStored (this.left);
+ var right = ec.EmitStored (this.right);
+
+ ec.EmitNullableHasValue (left);
+ ec.EmitNullableHasValue (right);
+ ig.Emit (OpCodes.And);
+ ig.Emit (OpCodes.Brfalse, ret);
+
+ ec.EmitNullableGetValueOrDefault (left);
+ ec.EmitNullableGetValueOrDefault (right);
+ ec.EmitCall (method);
+ ec.EmitNullableNew (Type);
+ ig.Emit (OpCodes.Br, done);
+
+ ig.MarkLabel (ret);
+ var temp = ig.DeclareLocal (Type);
+ ec.EmitNullableInitialize (temp);
+
+ ig.MarkLabel (done);
+ }
+
+ void EmitUserDefinedLiftedLogicalShortCircuit (EmitContext ec)
+ {
+ var ig = ec.ig;
+ var and = NodeType == ExpressionType.AndAlso;
+
+ var left_is_null = ig.DefineLabel ();
+ var ret_left = ig.DefineLabel ();
+ var ret_null = ig.DefineLabel ();
+ var done = ig.DefineLabel ();
+
+ var left = ec.EmitStored (this.left);
+
+ ec.EmitNullableHasValue (left);
+ ig.Emit (OpCodes.Brfalse, and ? ret_null : left_is_null);
+
+ ec.EmitNullableGetValueOrDefault (left);
+ ec.EmitCall (and ? GetFalseOperator () : GetTrueOperator ());
+ ig.Emit (OpCodes.Brtrue, ret_left);
+
+ ig.MarkLabel (left_is_null);
+ var right = ec.EmitStored (this.right);
+ ec.EmitNullableHasValue (right);
+ ig.Emit (OpCodes.Brfalse, ret_null);
+
+ ec.EmitNullableGetValueOrDefault (left);
+ ec.EmitNullableGetValueOrDefault (right);
+ ec.EmitCall (method);
+
+ ec.EmitNullableNew (Type);
+ ig.Emit (OpCodes.Br, done);
+
+ ig.MarkLabel (ret_left);
+ ec.EmitLoad (left);
+ ig.Emit (OpCodes.Br, done);
+
+ ig.MarkLabel (ret_null);
+ var ret = ig.DeclareLocal (Type);
+ ec.EmitNullableInitialize (ret);
+
+ ig.MarkLabel (done);
+ }
+
+ void EmitUserDefinedOperator (EmitContext ec)
+ {
+ if (!IsLifted) {
+ switch (NodeType) {
+ case ExpressionType.AndAlso:
+ case ExpressionType.OrElse:
+ EmitUserDefinedLogicalShortCircuit (ec);
+ break;
+ default:
+ left.Emit (ec);
+ right.Emit (ec);
+ ec.EmitCall (method);
+ break;
+ }
+ } else if (IsLiftedToNull) {
+ switch (NodeType) {
+ case ExpressionType.AndAlso:
+ case ExpressionType.OrElse:
+ EmitUserDefinedLiftedLogicalShortCircuit (ec);
+ break;
+ default:
+ EmitLiftedToNullUserDefinedOperator (ec);
+ break;
+ }
+ } else
+ EmitLiftedUserDefinedOperator (ec);
+ }
+
internal override void Emit (EmitContext ec)
{
- if (method != null){
- EmitMethod (ec);
+ if (method != null) {
+ EmitUserDefinedOperator (ec);
return;
}
EmitArrayAccess (ec);
return;
case ExpressionType.Coalesce:
- EmitCoalesce (ec);
+ if (conversion != null)
+ EmitConvertedCoalesce (ec);
+ else
+ EmitCoalesce (ec);
return;
case ExpressionType.Power:
- // likely broken if lifted
- left.Emit (ec);
- right.Emit (ec);
- ec.EmitCall (typeof (Math).GetMethod ("Pow"));
- return;
case ExpressionType.Add:
case ExpressionType.AddChecked:
case ExpressionType.Divide:
throw new NotSupportedException (this.NodeType.ToString ());
}
}
+#endif
}
}