// Marek Safar (marek.safar@gmail.com)
//
// Dual licensed under the terms of the MIT X11 or GNU GPL
-// Copyright 2003-2008 Novell, Inc.
+// Copyright 2003-2011 Novell, Inc.
+// Copyright 2011 Xamarin Inc
//
using System;
return Expr.CreateExpressionTree (ec);
}
+
+ public virtual void Emit (EmitContext ec)
+ {
+ if (!IsByRef) {
+ Expr.Emit (ec);
+ return;
+ }
+
+ AddressOp mode = AddressOp.Store;
+ if (ArgType == AType.Ref)
+ mode |= AddressOp.Load;
+
+ IMemoryLocation ml = (IMemoryLocation) Expr;
+ ml.AddressOf (ec, mode);
+ }
+
+ public Argument EmitToField (EmitContext ec, bool cloneResult)
+ {
+ var res = Expr.EmitToField (ec);
+ if (cloneResult && res != Expr)
+ return new Argument (res, ArgType);
+
+ Expr = res;
+ return this;
+ }
+
public string GetSignatureForError ()
{
if (Expr.eclass == ExprClass.MethodGroup)
public void Resolve (ResolveContext ec)
{
- if (Expr == EmptyExpression.Null)
- return;
-
// using (ec.With (ResolveContext.Options.DoFlowAnalysis, true)) {
// Verify that the argument is readable
if (ArgType != AType.Out)
Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess);
if (Expr == null)
- Expr = EmptyExpression.Null;
+ Expr = ErrorExpression.Instance;
// }
}
-
- public virtual void Emit (EmitContext ec)
- {
- if (!IsByRef) {
- Expr.Emit (ec);
- return;
- }
-
- AddressOp mode = AddressOp.Store;
- if (ArgType == AType.Ref)
- mode |= AddressOp.Load;
-
- IMemoryLocation ml = (IMemoryLocation) Expr;
- ml.AddressOf (ec, mode);
- }
}
- public class NamedArgument : Argument
+ public class MovableArgument : Argument
{
- public readonly string Name;
- readonly Location loc;
LocalTemporary variable;
- public NamedArgument (string name, Location loc, Expression expr)
- : this (name, loc, expr, AType.None)
+ public MovableArgument (Argument arg)
+ : this (arg.Expr, arg.ArgType)
{
}
- public NamedArgument (string name, Location loc, Expression expr, AType modifier)
+ protected MovableArgument (Expression expr, AType modifier)
: base (expr, modifier)
{
- this.Name = name;
- this.loc = loc;
- }
-
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- ec.Report.Error (853, loc, "An expression tree cannot contain named argument");
- return base.CreateExpressionTree (ec);
}
public override void Emit (EmitContext ec)
variable.Release (ec);
}
- public void EmitAssign (EmitContext ec)
+ public void EmitToVariable (EmitContext ec)
{
var type = Expr.Type;
if (IsByRef) {
var ml = (IMemoryLocation) Expr;
- ml.AddressOf (ec, AddressOp.Load);
+ ml.AddressOf (ec, AddressOp.LoadStore);
type = ReferenceContainer.MakeType (ec.Module, type);
} else {
Expr.Emit (ec);
Expr = variable;
}
+ }
+
+ public class NamedArgument : MovableArgument
+ {
+ public readonly string Name;
+ readonly Location loc;
+
+ public NamedArgument (string name, Location loc, Expression expr)
+ : this (name, loc, expr, AType.None)
+ {
+ }
+
+ public NamedArgument (string name, Location loc, Expression expr, AType modifier)
+ : base (expr, modifier)
+ {
+ this.Name = name;
+ this.loc = loc;
+ }
+
+ public override Expression CreateExpressionTree (ResolveContext ec)
+ {
+ ec.Report.Error (853, loc, "An expression tree cannot contain named argument");
+ return base.CreateExpressionTree (ec);
+ }
public Location Location {
get { return loc; }
{
sealed class ArgumentsOrdered : Arguments
{
- List<NamedArgument> ordered;
+ readonly List<MovableArgument> ordered;
public ArgumentsOrdered (Arguments args)
: base (args.Count)
{
AddRange (args);
- ordered = new List<NamedArgument> ();
+ ordered = new List<MovableArgument> ();
}
- public void AddOrdered (NamedArgument na)
+ public void AddOrdered (MovableArgument arg)
{
- ordered.Add (na);
+ ordered.Add (arg);
}
- public override Expression[] Emit (EmitContext ec, bool dup_args)
+ public override Arguments Emit (EmitContext ec, bool dup_args, bool prepareAwait)
{
- foreach (NamedArgument na in ordered)
- na.EmitAssign (ec);
+ foreach (var a in ordered) {
+ if (prepareAwait)
+ a.EmitToField (ec, false);
+ else
+ a.EmitToVariable (ec);
+ }
- return base.Emit (ec, dup_args);
+ return base.Emit (ec, dup_args, prepareAwait);
}
}
args = new List<Argument> (capacity);
}
+ private Arguments (List<Argument> args)
+ {
+ this.args = args;
+ }
+
public void Add (Argument arg)
{
args.Add (arg);
this.args.AddRange (args.args);
}
+ public bool ContainsEmitWithAwait ()
+ {
+ foreach (var arg in args) {
+ if (arg.Expr.ContainsEmitWithAwait ())
+ return true;
+ }
+
+ return false;
+ }
+
public ArrayInitializer CreateDynamicBinderArguments (ResolveContext rc)
{
Location loc = Location.Null;
if (a.Expr is Constant) {
info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
- new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "Constant", loc), loc);
+ new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "Constant", loc));
} else if (a.ArgType == Argument.AType.Ref) {
info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
- new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsRef", loc), loc);
+ new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsRef", loc));
info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
- new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc), loc);
+ new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc));
} else if (a.ArgType == Argument.AType.Out) {
info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
- new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsOut", loc), loc);
+ new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsOut", loc));
info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
- new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc), loc);
+ new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc));
} else if (a.ArgType == Argument.AType.DynamicTypeName) {
info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
- new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsStaticType", loc), loc);
+ new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsStaticType", loc));
}
var arg_type = a.Expr.Type;
}
info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
- new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc), loc);
+ new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc));
}
string named_value;
NamedArgument na = a as NamedArgument;
if (na != null) {
info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
- new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "NamedArgument", loc), loc);
+ new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "NamedArgument", loc));
named_value = na.Name;
} else {
//
public void Emit (EmitContext ec)
{
- Emit (ec, false);
+ Emit (ec, false, false);
}
//
- // if `dup_args' is true, a copy of the arguments will be left
- // on the stack and return value will contain an array of access
- // expressions
- // NOTE: It's caller responsibility is to release temporary variables
+ // if `dup_args' is true or any of arguments contains await.
+ // A copy of all arguments will be returned to the caller
//
- public virtual Expression[] Emit (EmitContext ec, bool dup_args)
+ public virtual Arguments Emit (EmitContext ec, bool dup_args, bool prepareAwait)
{
- Expression[] temps;
+ List<Argument> dups;
- if (dup_args && Count != 0)
- temps = new Expression [Count];
+ if ((dup_args && Count != 0) || prepareAwait)
+ dups = new List<Argument> (Count);
else
- temps = null;
+ dups = null;
- int i = 0;
LocalTemporary lt;
foreach (Argument a in args) {
+ if (prepareAwait) {
+ dups.Add (a.EmitToField (ec, true));
+ continue;
+ }
+
a.Emit (ec);
- if (!dup_args)
+
+ if (!dup_args) {
continue;
+ }
- if (a.Expr is Constant || a.Expr is This) {
+ if (a.Expr.IsSideEffectFree) {
//
- // No need to create a temporary variable for constants
+ // No need to create a temporary variable for side effect free expressions. I assume
+ // all side-effect free expressions are cheap, this has to be tweaked when we become
+ // more aggressive on detection
//
- temps[i] = a.Expr;
+ dups.Add (a);
} else {
ec.Emit (OpCodes.Dup);
- temps[i] = lt = new LocalTemporary (a.Type);
+
+ // TODO: Release local temporary on next Emit
+ // Need to add a flag to argument to indicate this
+ lt = new LocalTemporary (a.Type);
lt.Store (ec);
- }
- ++i;
+ dups.Add (new Argument (lt, a.ArgType));
+ }
}
- return temps;
+ if (dups != null)
+ return new Arguments (dups);
+
+ return null;
}
public List<Argument>.Enumerator GetEnumerator ()
public Arguments MarkOrderedArgument (NamedArgument a)
{
//
- // Constant expression have no effect on left-to-right execution
+ // An expression has no effect on left-to-right execution
//
- if (a.Expr is Constant)
+ if (a.Expr.IsSideEffectFree)
return this;
ArgumentsOrdered ra = this as ArgumentsOrdered;
- if (ra == null)
+ if (ra == null) {
ra = new ArgumentsOrdered (this);
+ for (int i = 0; i < args.Count; ++i) {
+ var la = args [i];
+ if (la == a)
+ break;
+
+ //
+ // When the argument is filled later by default expression
+ //
+ if (la == null)
+ continue;
+
+ var ma = la as MovableArgument;
+ if (ma == null) {
+ ma = new MovableArgument (la);
+ ra.args[i] = ma;
+ }
+
+ ra.AddOrdered (ma);
+ }
+ }
+
ra.AddOrdered (a);
return ra;
}