X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fargument.cs;h=13d0526cc2cd9c5a47e422bbdc2b9c763c2de9b4;hb=e554e95f150a3132e1e098b457135a470bd90217;hp=d578e3532b93c09ea1cd14856510d84deaf6a742;hpb=af9193d9cc7d6d03c0dfc6ca116a923c674c2db7;p=mono.git diff --git a/mcs/mcs/argument.cs b/mcs/mcs/argument.cs index d578e3532b9..13d0526cc2c 100644 --- a/mcs/mcs/argument.cs +++ b/mcs/mcs/argument.cs @@ -6,13 +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.Emit; using System.Collections.Generic; +#if STATIC +using IKVM.Reflection.Emit; +#else +using System.Reflection.Emit; +#endif + namespace Mono.CSharp { // @@ -41,9 +47,6 @@ namespace Mono.CSharp public Argument (Expression expr) { - if (expr == null) - throw new ArgumentNullException (); - this.Expr = expr; } @@ -98,12 +101,61 @@ 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 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 TypeManager.CSharpName (Expr.Type); + return Expr.Type.GetSignatureForError (); } public bool ResolveMethodGroup (ResolveContext ec) @@ -123,61 +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); + 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) @@ -190,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); } @@ -206,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; } @@ -216,26 +262,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); } } @@ -247,6 +297,11 @@ namespace Mono.CSharp args = new List (capacity); } + private Arguments (List args) + { + this.args = args; + } + public void Add (Argument arg) { args.Add (arg); @@ -257,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; @@ -269,29 +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); 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; - if (arg_type != InternalType.Dynamic && arg_type != InternalType.Null) { + 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, @@ -300,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 { @@ -322,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)); } @@ -378,46 +443,81 @@ 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); + + dups.Add (new Argument (lt, a.ArgType)); } + } + + if (dups != null) + return new Arguments (dups); + + return null; + } - ++i; + 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); } - return temps; + if (!has_out) + return; + + foreach (var arg in args) { + if (arg.ArgType != Argument.AType.Out) + continue; + + arg.FlowAnalysis (fc); + } } public List.Enumerator GetEnumerator () @@ -431,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; } @@ -480,15 +580,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; } @@ -501,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; } }