X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mcs%2Fmcs%2Fargument.cs;h=22e28eaf7290267fa3754ecd6666cbd1e2f15cad;hb=3d43cfdfccc1aa699e599c39f91fb41231304da9;hp=4acd366f72b5a3eaca196d562b5f9be8d97eb173;hpb=f27a0795926783c5f7338543477f174aa14b76d0;p=mono.git diff --git a/mcs/mcs/argument.cs b/mcs/mcs/argument.cs index 4acd366f72b..22e28eaf729 100644 --- a/mcs/mcs/argument.cs +++ b/mcs/mcs/argument.cs @@ -6,7 +6,8 @@ // 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; @@ -103,6 +104,32 @@ namespace Mono.CSharp 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) @@ -128,9 +155,6 @@ namespace Mono.CSharp 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) @@ -141,48 +165,23 @@ namespace Mono.CSharp 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) @@ -195,12 +194,12 @@ namespace Mono.CSharp 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); @@ -211,6 +210,30 @@ namespace Mono.CSharp 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; } @@ -221,26 +244,30 @@ namespace Mono.CSharp { sealed class ArgumentsOrdered : Arguments { - List ordered; + readonly List ordered; public ArgumentsOrdered (Arguments args) : base (args.Count) { AddRange (args); - ordered = new List (); + ordered = new List (); } - 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); } } @@ -252,6 +279,11 @@ namespace Mono.CSharp args = new List (capacity); } + private Arguments (List args) + { + this.args = args; + } + public void Add (Argument arg) { args.Add (arg); @@ -262,6 +294,16 @@ namespace Mono.CSharp 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; @@ -278,20 +320,20 @@ namespace Mono.CSharp 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; @@ -312,14 +354,14 @@ namespace Mono.CSharp } 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 { @@ -383,46 +425,58 @@ namespace Mono.CSharp // 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 dups; - if (dup_args && Count != 0) - temps = new Expression [Count]; + if ((dup_args && Count != 0) || prepareAwait) + dups = new List (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.Enumerator GetEnumerator () @@ -485,15 +539,36 @@ namespace Mono.CSharp 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; }