X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mcs%2Fmcs%2Fargument.cs;h=13d0526cc2cd9c5a47e422bbdc2b9c763c2de9b4;hb=e554e95f150a3132e1e098b457135a470bd90217;hp=8cb7e9780e38b25ff0c97f9bb527d2bd7d20b481;hpb=92f60fbffa1187be7dedf6a9286b5c35b2082815;p=mono.git diff --git a/mcs/mcs/argument.cs b/mcs/mcs/argument.cs index 8cb7e9780e3..13d0526cc2c 100644 --- a/mcs/mcs/argument.cs +++ b/mcs/mcs/argument.cs @@ -6,14 +6,19 @@ // 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; -using System.Reflection; -using System.Reflection.Emit; using System.Collections.Generic; +#if STATIC +using IKVM.Reflection.Emit; +#else +using System.Reflection.Emit; +#endif + namespace Mono.CSharp { // @@ -42,14 +47,17 @@ namespace Mono.CSharp public Argument (Expression expr) { - if (expr == null) - throw new ArgumentNullException (); - this.Expr = expr; } - public TypeSpec Type { - get { return Expr.Type; } + #region Properties + + public bool IsByRef { + get { return ArgType == AType.Ref || ArgType == AType.Out; } + } + + public bool IsDefaultArgument { + get { return ArgType == AType.Default; } } public Parameter.Modifier Modifier { @@ -67,6 +75,24 @@ namespace Mono.CSharp } } + public TypeSpec Type { + get { return Expr.Type; } + } + + #endregion + + public Argument Clone (Expression expr) + { + Argument a = (Argument) MemberwiseClone (); + a.Expr = expr; + return a; + } + + public Argument Clone (CloneContext clonectx) + { + return Clone (Expr.Clone (clonectx)); + } + public virtual Expression CreateExpressionTree (ResolveContext ec) { if (ArgType == AType.Default) @@ -75,20 +101,61 @@ namespace Mono.CSharp return Expr.CreateExpressionTree (ec); } - public string GetSignatureForError () + + public virtual void Emit (EmitContext ec) { - if (Expr.eclass == ExprClass.MethodGroup) - return Expr.ExprClassName; + if (!IsByRef) { + Expr.Emit (ec); + return; + } - return TypeManager.CSharpName (Expr.Type); + AddressOp mode = AddressOp.Store; + if (ArgType == AType.Ref) + mode |= AddressOp.Load; + + IMemoryLocation ml = (IMemoryLocation) Expr; + ml.AddressOf (ec, mode); } - public bool IsByRef { - get { return ArgType == AType.Ref || ArgType == AType.Out; } + 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 bool IsDefaultArgument { - get { return ArgType == AType.Default; } + public void FlowAnalysis (FlowAnalysisContext fc) + { + if (ArgType == AType.Out) { + var vr = Expr as VariableReference; + if (vr != null) { + if (vr.VariableInfo != null) + fc.SetVariableAssigned (vr.VariableInfo); + + return; + } + + var fe = Expr as FieldExpr; + if (fe != null) { + fe.SetFieldAssigned (fc); + return; + } + + return; + } + + Expr.FlowAnalysis (fc); + } + + public string GetSignatureForError () + { + if (Expr.eclass == ExprClass.MethodGroup) + return Expr.ExprClassName; + + return Expr.Type.GetSignatureForError (); } public bool ResolveMethodGroup (ResolveContext ec) @@ -108,68 +175,31 @@ 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) - Expr = Expr.Resolve (ec); - - // Verify that the argument is writeable - if (Expr != null && IsByRef) - Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess.Instance); - - if (Expr == null) - Expr = EmptyExpression.Null; -// } - } - - public virtual void Emit (EmitContext ec) - { - if (!IsByRef) { - Expr.Emit (ec); - return; - } + // Verify that the argument is readable + if (ArgType != AType.Out) + Expr = Expr.Resolve (ec); - AddressOp mode = AddressOp.Store; - if (ArgType == AType.Ref) - mode |= AddressOp.Load; + // Verify that the argument is writeable + if (Expr != null && IsByRef) + Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess); - IMemoryLocation ml = (IMemoryLocation) Expr; - ml.AddressOf (ec, mode); - } - - public Argument Clone (CloneContext clonectx) - { - Argument a = (Argument) MemberwiseClone (); - a.Expr = Expr.Clone (clonectx); - return a; + if (Expr == null) + Expr = ErrorExpression.Instance; } } - 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) @@ -182,13 +212,13 @@ 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); - type = ReferenceContainer.MakeType (type); + ml.AddressOf (ec, AddressOp.LoadStore); + type = ReferenceContainer.MakeType (ec.Module, type); } else { Expr.Emit (ec); } @@ -198,6 +228,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; } @@ -206,14 +260,48 @@ namespace Mono.CSharp public class Arguments { + sealed class ArgumentsOrdered : Arguments + { + readonly List ordered; + + public ArgumentsOrdered (Arguments args) + : base (args.Count) + { + AddRange (args); + ordered = new List (); + } + + public void AddOrdered (MovableArgument arg) + { + ordered.Add (arg); + } + + public override Arguments Emit (EmitContext ec, bool dup_args, bool prepareAwait) + { + foreach (var a in ordered) { + if (prepareAwait) + a.EmitToField (ec, false); + else + a.EmitToVariable (ec); + } + + return base.Emit (ec, dup_args, prepareAwait); + } + } + + // Try not to add any more instances to this class, it's allocated a lot List args; - List reordered; public Arguments (int capacity) { args = new List (capacity); } + private Arguments (List args) + { + this.args = args; + } + public void Add (Argument arg) { args.Add (arg); @@ -224,6 +312,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; @@ -236,26 +334,29 @@ namespace Mono.CSharp // CSharpArgumentInfoFlags.None = 0 const string info_flags_enum = "CSharpArgumentInfoFlags"; - Expression info_flags = new IntLiteral (0, loc); + Expression info_flags = new IntLiteral (rc.BuiltinTypes, 0, loc); - var constant = a.Expr as Constant; - if (constant != null && constant.IsLiteral) { + 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)); } 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)); } 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; - if (arg_type != InternalType.Dynamic) { + if (arg_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic && arg_type != InternalType.NullLiteral) { MethodGroupExpr mg = a.Expr as MethodGroupExpr; if (mg != null) { rc.Report.Error (1976, a.Expr.Location, @@ -264,21 +365,21 @@ namespace Mono.CSharp } else if (arg_type == InternalType.AnonymousMethod) { rc.Report.Error (1977, a.Expr.Location, "An anonymous method or lambda expression cannot be used as an argument of dynamic operation. Consider using a cast"); - } else if (arg_type == TypeManager.void_type || arg_type == InternalType.Arglist || arg_type.IsPointer) { + } else if (arg_type.Kind == MemberKind.Void || arg_type == InternalType.Arglist || arg_type.IsPointer) { rc.Report.Error (1978, a.Expr.Location, "An expression of type `{0}' cannot be used as an argument of dynamic operation", - TypeManager.CSharpName (arg_type)); + arg_type.GetSignatureForError ()); } 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 { @@ -286,7 +387,7 @@ namespace Mono.CSharp } dargs.Add (new Argument (info_flags)); - dargs.Add (new Argument (new StringLiteral (named_value, loc))); + dargs.Add (new Argument (new StringLiteral (rc.BuiltinTypes, named_value, loc))); all.Add (new Invocation (new MemberAccess (new MemberAccess (binder, "CSharpArgumentInfo", loc), "Create", loc), dargs)); } @@ -342,44 +443,80 @@ namespace Mono.CSharp // public void Emit (EmitContext ec) { - Emit (ec, false, null); + Emit (ec, false, false); } // - // if `dup_args' is true, a copy of the arguments will be left - // on the stack. If `dup_args' is true, you can specify `this_arg' - // which will be duplicated before any other args. Only EmitCall - // should be using this interface. + // if `dup_args' is true or any of arguments contains await. + // A copy of all arguments will be returned to the caller // - public void Emit (EmitContext ec, bool dup_args, LocalTemporary this_arg) + public virtual Arguments Emit (EmitContext ec, bool dup_args, bool prepareAwait) { - LocalTemporary[] temps = null; - - if (dup_args && Count != 0) - temps = new LocalTemporary [Count]; + List dups; - if (reordered != null && Count > 1) { - foreach (NamedArgument na in reordered) - na.EmitAssign (ec); - } + if ((dup_args && Count != 0) || prepareAwait) + dups = new List (Count); + else + 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.IsSideEffectFree) { + // + // 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 + // + dups.Add (a); + } else { ec.Emit (OpCodes.Dup); - (temps [i++] = new LocalTemporary (a.Type)).Store (ec); + + // 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); + + dups.Add (new Argument (lt, a.ArgType)); } } - if (dup_args) { - if (this_arg != null) - this_arg.Emit (ec); + if (dups != null) + return new Arguments (dups); - for (i = 0; i < temps.Length; i++) { - temps[i].Emit (ec); - temps[i].Release (ec); + return null; + } + + public void FlowAnalysis (FlowAnalysisContext fc) + { + bool has_out = false; + foreach (var arg in args) { + if (arg.ArgType == Argument.AType.Out) { + has_out = true; + continue; } + + arg.FlowAnalysis (fc); + } + + if (!has_out) + return; + + foreach (var arg in args) { + if (arg.ArgType != Argument.AType.Out) + continue; + + arg.FlowAnalysis (fc); } } @@ -394,7 +531,7 @@ namespace Mono.CSharp public bool HasDynamic { get { foreach (Argument a in args) { - if (a.Type == InternalType.Dynamic && !a.IsByRef) + if (a.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && !a.IsByRef) return true; } @@ -402,6 +539,21 @@ namespace Mono.CSharp } } + // + // At least one argument is named argument + // + public bool HasNamed { + get { + foreach (Argument a in args) { + if (a is NamedArgument) + return true; + } + + return false; + } + } + + public void Insert (int index, Argument arg) { args.Insert (index, arg); @@ -421,18 +573,45 @@ namespace Mono.CSharp return exprs; } - public void MarkReorderedArgument (NamedArgument a) + // + // For named arguments when the order of execution is different + // to order of invocation + // + public Arguments MarkOrderedArgument (NamedArgument a) { // - // Constant expression can have no effect on left-to-right execution + // An expression has no effect on left-to-right execution // - if (a.Expr is Constant) - return; + if (a.Expr.IsSideEffectFree) + return this; + + ArgumentsOrdered ra = this as ArgumentsOrdered; + 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; + } - if (reordered == null) - reordered = new List (); + ra.AddOrdered (ma); + } + } - reordered.Add (a); + ra.AddOrdered (a); + return ra; } // @@ -443,7 +622,7 @@ namespace Mono.CSharp dynamic = false; foreach (Argument a in args) { a.Resolve (ec); - if (a.Type == InternalType.Dynamic && !a.IsByRef) + if (a.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && !a.IsByRef) dynamic = true; } }