X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fasync.cs;h=6de09f01b1a9d83ff4a899f8cff922549a19e19d;hb=f3edca943070399b06d33f3ba3e99c76a9d9886d;hp=805d43cfdec242d6f270e91106b600a6670b3913;hpb=71be73bff4bb7f11f09e7adfadd1f1ffa6c4df08;p=mono.git diff --git a/mcs/mcs/async.cs b/mcs/mcs/async.cs index 805d43cfdec..6de09f01b1a 100644 --- a/mcs/mcs/async.cs +++ b/mcs/mcs/async.cs @@ -7,7 +7,7 @@ // Dual licensed under the terms of the MIT X11 or GNU GPL // // Copyright 2011 Novell, Inc. -// Copyright 2011 Xamarin Inc. +// Copyright 2011-2012 Xamarin Inc. // using System; @@ -16,8 +16,10 @@ using System.Linq; using System.Collections; #if STATIC +using IKVM.Reflection; using IKVM.Reflection.Emit; #else +using System.Reflection; using System.Reflection.Emit; #endif @@ -40,6 +42,12 @@ namespace Mono.CSharp } } + public AwaitStatement Statement { + get { + return stmt; + } + } + protected override void CloneTo (CloneContext clonectx, Expression target) { var t = (Await) target; @@ -113,7 +121,7 @@ namespace Mono.CSharp } } - class AwaitStatement : YieldStatement + public class AwaitStatement : YieldStatement { sealed class AwaitableMemberAccess : MemberAccess { @@ -207,13 +215,17 @@ namespace Mono.CSharp public void EmitPrologue (EmitContext ec) { + awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (expr.Type, loc); + var fe_awaiter = new FieldExpr (awaiter, loc); fe_awaiter.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc); // // awaiter = expr.GetAwaiter (); // - fe_awaiter.EmitAssign (ec, expr, false, false); + using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) { + fe_awaiter.EmitAssign (ec, expr, false, false); + } Label skip_continuation = ec.DefineLabel (); @@ -268,14 +280,10 @@ namespace Mono.CSharp EmitPrologue (ec); DoEmit (ec); - if (ResultType.Kind != MemberKind.Void) { - var storey = (AsyncTaskStorey) machine_initializer.Storey; + awaiter.IsAvailableForReuse = true; - if (storey.HoistedReturn != null) - storey.HoistedReturn.EmitAssign (ec); - else - ec.Emit (OpCodes.Pop); - } + if (ResultType.Kind != MemberKind.Void) + ec.Emit (OpCodes.Pop); } void Error_WrongAwaiterPattern (ResolveContext rc, TypeSpec awaiter) @@ -304,9 +312,6 @@ namespace Mono.CSharp // if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { result_type = type; - - awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (type, loc); - expr = new Invocation (new MemberAccess (expr, "GetAwaiter"), args).Resolve (bc); return true; } @@ -332,8 +337,6 @@ namespace Mono.CSharp } var awaiter_type = ama.Type; - awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (awaiter_type, loc); - expr = ama; // @@ -400,12 +403,6 @@ namespace Mono.CSharp } } - public Block OriginalBlock { - get { - return block.Parent; - } - } - public TypeInferenceContext ReturnTypeInference { get { return return_inference; @@ -414,38 +411,6 @@ namespace Mono.CSharp #endregion - public static void Create (IMemberContext context, ParametersBlock block, ParametersCompiled parameters, TypeDefinition host, TypeSpec returnType, Location loc) - { - for (int i = 0; i < parameters.Count; i++) { - Parameter p = parameters[i]; - Parameter.Modifier mod = p.ModFlags; - if ((mod & Parameter.Modifier.RefOutMask) != 0) { - host.Compiler.Report.Error (1988, p.Location, - "Async methods cannot have ref or out parameters"); - return; - } - - if (p is ArglistParameter) { - host.Compiler.Report.Error (4006, p.Location, - "__arglist is not allowed in parameter list of async methods"); - return; - } - - if (parameters.Types[i].IsPointer) { - host.Compiler.Report.Error (4005, p.Location, - "Async methods cannot have unsafe parameters"); - return; - } - } - - if (!block.HasAwait) { - host.Compiler.Report.Warning (1998, 1, loc, - "Async block lacks `await' operator and will run synchronously"); - } - - block.WrapIntoAsyncTask (context, host, returnType); - } - protected override BlockContext CreateBlockContext (ResolveContext rc) { var ctx = base.CreateBlockContext (rc); @@ -493,12 +458,14 @@ namespace Mono.CSharp PropertySpec task; LocalVariable hoisted_return; int locals_captured; - Dictionary> stack_fields; + Dictionary> stack_fields; + Dictionary> awaiter_fields; - public AsyncTaskStorey (IMemberContext context, AsyncInitializer initializer, TypeSpec type) - : base (initializer.OriginalBlock, initializer.Host, context.CurrentMemberDefinition as MemberBase, context.CurrentTypeParameters, "async", MemberKind.Class) + public AsyncTaskStorey (ParametersBlock block, IMemberContext context, AsyncInitializer initializer, TypeSpec type) + : base (block, initializer.Host, context.CurrentMemberDefinition as MemberBase, context.CurrentTypeParameters, "async", MemberKind.Struct) { return_type = type; + awaiter_fields = new Dictionary> (); } #region Properties @@ -521,38 +488,63 @@ namespace Mono.CSharp } } + protected override TypeAttributes TypeAttr { + get { + return base.TypeAttr & ~TypeAttributes.SequentialLayout; + } + } + #endregion public Field AddAwaiter (TypeSpec type, Location loc) { - return AddCapturedVariable ("$awaiter" + awaiters++.ToString ("X"), type); + if (mutator != null) + type = mutator.Mutate (type); + + List existing_fields = null; + if (awaiter_fields.TryGetValue (type, out existing_fields)) { + foreach (var f in existing_fields) { + if (f.IsAvailableForReuse) { + f.IsAvailableForReuse = false; + return f; + } + } + } + + var field = AddCompilerGeneratedField ("$awaiter" + awaiters++.ToString ("X"), new TypeExpression (type, Location), true); + field.Define (); + + if (existing_fields == null) { + existing_fields = new List (); + awaiter_fields.Add (type, existing_fields); + } + + existing_fields.Add (field); + return field; } - public StackField AddCapturedLocalVariable (TypeSpec type) + public Field AddCapturedLocalVariable (TypeSpec type) { if (mutator != null) type = mutator.Mutate (type); - List existing_fields = null; + List existing_fields = null; if (stack_fields == null) { - stack_fields = new Dictionary> (); + stack_fields = new Dictionary> (); } else if (stack_fields.TryGetValue (type, out existing_fields)) { foreach (var f in existing_fields) { - if (f.CanBeReused) { - f.CanBeReused = false; + if (f.IsAvailableForReuse) { + f.IsAvailableForReuse = false; return f; } } } - const Modifiers mod = Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE; - var field = new StackField (this, new TypeExpression (type, Location), mod, new MemberName ("$stack" + locals_captured++.ToString ("X"), Location)); - AddField (field); - + var field = AddCompilerGeneratedField ("$stack" + locals_captured++.ToString ("X"), new TypeExpression (type, Location), true); field.Define (); if (existing_fields == null) { - existing_fields = new List (); + existing_fields = new List (); stack_fields.Add (type, existing_fields); } @@ -761,16 +753,10 @@ namespace Mono.CSharp InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location) }; - // TODO: CompilerGeneratedThis is enough for structs - var temp_this = new LocalTemporary (CurrentType); - temp_this.EmitAssign (ec, new CompilerGeneratedThis (CurrentType, Location), false, false); - var args = new Arguments (2); args.Add (new Argument (awaiter, Argument.AType.Ref)); - args.Add (new Argument (temp_this, Argument.AType.Ref)); + args.Add (new Argument (new CompilerGeneratedThis (CurrentType, Location), Argument.AType.Ref)); mg.EmitCall (ec, args); - - temp_this.Release (ec); } public void EmitInitializer (EmitContext ec) @@ -800,14 +786,14 @@ namespace Mono.CSharp // // stateMachine.$builder = AsyncTaskMethodBuilder<{task-type}>.Create(); // - instance.Emit (ec); // .AddressOf (ec, AddressOp.Store); + instance.AddressOf (ec, AddressOp.Store); ec.Emit (OpCodes.Call, builder_factory); ec.Emit (OpCodes.Stfld, builder_field); // // stateMachine.$builder.Start<{storey-type}>(ref stateMachine); // - instance.Emit (ec); //.AddressOf (ec, AddressOp.Store); + instance.AddressOf (ec, AddressOp.Store); ec.Emit (OpCodes.Ldflda, builder_field); if (Task != null) ec.Emit (OpCodes.Dup); @@ -873,7 +859,7 @@ namespace Mono.CSharp protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class) { - base_type = Compiler.BuiltinTypes.Object; // ValueType; + base_type = Compiler.BuiltinTypes.ValueType; base_class = null; var istate_machine = Module.PredefinedTypes.IAsyncStateMachine; @@ -885,29 +871,42 @@ namespace Mono.CSharp } } - class StackField : Field + class StackFieldExpr : FieldExpr, IExpressionCleanup { - public StackField (TypeDefinition parent, FullNamedExpression type, Modifiers mod, MemberName name) - : base (parent, type, mod, name, null) + public StackFieldExpr (Field field) + : base (field, Location.Null) { } - public bool CanBeReused { get; set; } - } - - class StackFieldExpr : FieldExpr - { - public StackFieldExpr (Field field) - : base (field, Location.Null) + public override void AddressOf (EmitContext ec, AddressOp mode) { + base.AddressOf (ec, mode); + + if (mode == AddressOp.Load) { + var field = (Field) spec.MemberDefinition; + field.IsAvailableForReuse = true; + } } public override void Emit (EmitContext ec) { base.Emit (ec); - var field = (StackField) spec.MemberDefinition; - field.CanBeReused = true; + var field = (Field) spec.MemberDefinition; + field.IsAvailableForReuse = true; + + // + // Release any captured reference type stack variables + // to imitate real stack behavour and help GC stuff early + // + if (TypeSpec.IsReferenceType (type)) { + ec.AddStatementEpilog (this); + } + } + + void IExpressionCleanup.EmitCleanup (EmitContext ec) + { + EmitAssign (ec, new NullConstant (type, loc), false, false); } } }