示例#1
0
        public void EmitSetResult(EmitContext ec)
        {
            //
            // $builder.SetResult ();
            // $builder.SetResult<return-type> (value);
            //
            var mg = MethodGroupExpr.CreatePredefined(set_result, set_result.DeclaringType, Location);

            mg.InstanceExpression = new FieldExpr(builder, Location)
            {
                InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, Location)
            };

            Arguments args;

            if (HoistedReturnValue == null)
            {
                args = new Arguments(0);
            }
            else
            {
                args = new Arguments(1);
                args.Add(new Argument(HoistedReturnValue));
            }

            using (ec.With(BuilderContext.Options.OmitDebugInfo, true)) {
                mg.EmitCall(ec, args, true);
            }
        }
示例#2
0
        public void EmitSetResult(EmitContext ec)
        {
            //
            // $builder.SetResult ();
            // $builder.SetResult<return-type> (value);
            //
            var mg = MethodGroupExpr.CreatePredefined(set_result, set_result.DeclaringType, Location);

            mg.InstanceExpression = new FieldExpr(builder, Location)
            {
                InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, Location)
            };

            Arguments args;

            if (hoisted_return == null)
            {
                args = new Arguments(0);
            }
            else
            {
                args = new Arguments(1);
                args.Add(new Argument(new LocalVariableReference(hoisted_return, Location)));
            }

            mg.EmitCall(ec, args);
        }
示例#3
0
        public void EmitPrologue(EmitContext ec)
        {
            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);

            is_completed.InstanceExpression = fe_awaiter;
            is_completed.EmitBranchable(ec, resume_point, true);

            var mg_completed = MethodGroupExpr.CreatePredefined(on_completed, fe_awaiter.Type, loc);

            mg_completed.InstanceExpression = fe_awaiter;

            var args    = new Arguments(1);
            var storey  = (AsyncTaskStorey)machine_initializer.Storey;
            var fe_cont = new FieldExpr(storey.Continuation, loc);

            fe_cont.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            args.Add(new Argument(fe_cont));

            //
            // awaiter.OnCompleted (continuation);
            //
            mg_completed.EmitCall(ec, args);

            base.DoEmit(ec);
        }
示例#4
0
        private void EmitOnCompleted(EmitContext ec, Expression awaiter, bool unsafeVersion)
        {
            var pm = Module.PredefinedMembers;
            PredefinedMember <MethodSpec> predefined;
            bool has_task_return_type = false;

            if (return_type.Kind == MemberKind.Void)
            {
                predefined = unsafeVersion ? pm.AsyncVoidMethodBuilderOnCompletedUnsafe : pm.AsyncVoidMethodBuilderOnCompleted;
            }
            else if (return_type == Module.PredefinedTypes.Task.TypeSpec)
            {
                predefined = unsafeVersion ? pm.AsyncTaskMethodBuilderOnCompletedUnsafe : pm.AsyncTaskMethodBuilderOnCompleted;
            }
            else
            {
                predefined           = unsafeVersion ? pm.AsyncTaskMethodBuilderGenericOnCompletedUnsafe : pm.AsyncTaskMethodBuilderGenericOnCompleted;
                has_task_return_type = true;
            }

            var on_completed = predefined.Resolve(Location);

            if (on_completed == null)
            {
                return;
            }

            if (has_task_return_type)
            {
                on_completed = MemberCache.GetMember <MethodSpec>(set_result.DeclaringType, on_completed);
            }

            on_completed = on_completed.MakeGenericMethod(this, awaiter.Type, ec.CurrentType);

            var mg = MethodGroupExpr.CreatePredefined(on_completed, on_completed.DeclaringType, Location);

            mg.InstanceExpression = new FieldExpr(builder, Location)
            {
                InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, Location)
            };

            var args = new Arguments(2);

            args.Add(new Argument(awaiter, Argument.AType.Ref));
            args.Add(new Argument(new CompilerGeneratedThis(CurrentType, Location), Argument.AType.Ref));
            using (ec.With(BuilderContext.Options.OmitDebugInfo, true))
            {
                mg.EmitCall(ec, args, true);
            }
        }
示例#5
0
        public override Expression CreateExpressionTree(ResolveContext ec)
        {
            Arguments args = new Arguments(2);

            args.Add(new Argument(new TypeOf(type, loc)));

            if (method_group.InstanceExpression == null)
            {
                args.Add(new Argument(new NullLiteral(loc)));
            }
            else
            {
                args.Add(new Argument(method_group.InstanceExpression));
            }

            Expression ma;
            var        create_v45 = ec.Module.PredefinedMembers.MethodInfoCreateDelegate.Get();

            if (create_v45 != null)
            {
                //
                // .NET 4.5 has better API but it produces different instance than Delegate::CreateDelegate
                // and because csc uses this enhancement we have to as well to be fully compatible
                //
                var mg = MethodGroupExpr.CreatePredefined(create_v45, create_v45.DeclaringType, loc);
                mg.InstanceExpression = method_group.CreateExpressionTree(ec);
                ma = mg;
            }
            else
            {
                ma = new MemberAccess(new MemberAccess(new QualifiedAliasMember("global", "System", loc), "Delegate", loc), "CreateDelegate", loc);
                args.Add(new Argument(method_group.CreateExpressionTree(ec)));
            }

            Expression e = new Invocation(ma, args).Resolve(ec);

            if (e == null)
            {
                return(null);
            }

            e = Convert.ExplicitConversion(ec, e, type, loc);
            if (e == null)
            {
                return(null);
            }

            return(e.CreateExpressionTree(ec));
        }
示例#6
0
        protected override void DoEmit(EmitContext ec)
        {
            var fe_awaiter = new FieldExpr(awaiter, loc);

            fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            //
            // result = awaiter.GetResult ();
            //
            var mg_result = MethodGroupExpr.CreatePredefined(get_result, fe_awaiter.Type, loc);

            mg_result.InstanceExpression = fe_awaiter;

            mg_result.EmitCall(ec, new Arguments(0));
        }
示例#7
0
        public void EmitSetException(EmitContext ec, LocalVariableReference exceptionVariable)
        {
            //
            // $builder.SetException (Exception)
            //
            var mg = MethodGroupExpr.CreatePredefined(set_exception, set_exception.DeclaringType, Location);

            mg.InstanceExpression = new FieldExpr(builder, Location)
            {
                InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, Location)
            };

            Arguments args = new Arguments(1);

            args.Add(new Argument(exceptionVariable));

            mg.EmitCall(ec, args);
        }
示例#8
0
        public Expression GetResultExpression(EmitContext ec)
        {
            var fe_awaiter = new FieldExpr(awaiter, loc);

            fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            //
            // result = awaiter.GetResult ();
            //
            if (IsDynamic)
            {
                var rc = new ResolveContext(ec.MemberContext);
                return(new Invocation(new MemberAccess(fe_awaiter, "GetResult"), new Arguments(0)).Resolve(rc));
            }

            var mg_result = MethodGroupExpr.CreatePredefined(awaiter_definition.GetResult, fe_awaiter.Type, loc);

            mg_result.InstanceExpression = fe_awaiter;

            return(new GetResultInvocation(mg_result, new Arguments(0)));
        }
示例#9
0
        protected override bool DoDefineMembers()
        {
            PredefinedType builder_type;
            PredefinedMember <MethodSpec> bf;
            PredefinedMember <MethodSpec> bs;
            PredefinedMember <MethodSpec> sr;
            PredefinedMember <MethodSpec> se;
            PredefinedMember <MethodSpec> sm;
            bool has_task_return_type = false;
            var  pred_members         = Module.PredefinedMembers;

            if (return_type.Kind == MemberKind.Void)
            {
                builder_type = Module.PredefinedTypes.AsyncVoidMethodBuilder;
                bf           = pred_members.AsyncVoidMethodBuilderCreate;
                bs           = pred_members.AsyncVoidMethodBuilderStart;
                sr           = pred_members.AsyncVoidMethodBuilderSetResult;
                se           = pred_members.AsyncVoidMethodBuilderSetException;
                sm           = pred_members.AsyncVoidMethodBuilderSetStateMachine;
            }
            else if (return_type == Module.PredefinedTypes.Task.TypeSpec)
            {
                builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilder;
                bf           = pred_members.AsyncTaskMethodBuilderCreate;
                bs           = pred_members.AsyncTaskMethodBuilderStart;
                sr           = pred_members.AsyncTaskMethodBuilderSetResult;
                se           = pred_members.AsyncTaskMethodBuilderSetException;
                sm           = pred_members.AsyncTaskMethodBuilderSetStateMachine;
                task         = pred_members.AsyncTaskMethodBuilderTask.Get();
            }
            else
            {
                builder_type         = Module.PredefinedTypes.AsyncTaskMethodBuilderGeneric;
                bf                   = pred_members.AsyncTaskMethodBuilderGenericCreate;
                bs                   = pred_members.AsyncTaskMethodBuilderGenericStart;
                sr                   = pred_members.AsyncTaskMethodBuilderGenericSetResult;
                se                   = pred_members.AsyncTaskMethodBuilderGenericSetException;
                sm                   = pred_members.AsyncTaskMethodBuilderGenericSetStateMachine;
                task                 = pred_members.AsyncTaskMethodBuilderGenericTask.Get();
                has_task_return_type = true;
            }

            set_result      = sr.Get();
            set_exception   = se.Get();
            builder_factory = bf.Get();
            builder_start   = bs.Get();

            var istate_machine   = Module.PredefinedTypes.IAsyncStateMachine;
            var set_statemachine = sm.Get();

            if (!builder_type.Define() || !istate_machine.Define() || set_result == null || builder_factory == null ||
                set_exception == null || set_statemachine == null || builder_start == null ||
                !Module.PredefinedTypes.INotifyCompletion.Define())
            {
                Report.Error(1993, Location,
                             "Cannot find compiler required types for asynchronous functions support. Are you targeting the wrong framework version?");
                return(base.DoDefineMembers());
            }

            var bt = builder_type.TypeSpec;

            //
            // Inflate generic Task types
            //
            if (has_task_return_type)
            {
                var task_return_type = return_type.TypeArguments;
                if (mutator != null)
                {
                    task_return_type = mutator.Mutate(task_return_type);
                }

                bt               = bt.MakeGenericType(Module, task_return_type);
                set_result       = MemberCache.GetMember(bt, set_result);
                set_exception    = MemberCache.GetMember(bt, set_exception);
                set_statemachine = MemberCache.GetMember(bt, set_statemachine);

                if (task != null)
                {
                    task = MemberCache.GetMember(bt, task);
                }
            }

            builder = AddCompilerGeneratedField("$builder", new TypeExpression(bt, Location));

            var set_state_machine = new Method(this, new TypeExpression(Compiler.BuiltinTypes.Void, Location),
                                               Modifiers.COMPILER_GENERATED | Modifiers.DEBUGGER_HIDDEN | Modifiers.PUBLIC,
                                               new MemberName("SetStateMachine"),
                                               ParametersCompiled.CreateFullyResolved(
                                                   new Parameter(new TypeExpression(istate_machine.TypeSpec, Location), "stateMachine", Parameter.Modifier.NONE, null, Location),
                                                   istate_machine.TypeSpec),
                                               null);

            ToplevelBlock block = new ToplevelBlock(Compiler, set_state_machine.ParameterInfo, Location);

            block.IsCompilerGenerated = true;
            set_state_machine.Block   = block;

            Members.Add(set_state_machine);

            if (!base.DoDefineMembers())
            {
                return(false);
            }

            //
            // Fabricates SetStateMachine method
            //
            // public void SetStateMachine (IAsyncStateMachine stateMachine)
            // {
            //    $builder.SetStateMachine (stateMachine);
            // }
            //
            var mg = MethodGroupExpr.CreatePredefined(set_statemachine, bt, Location);

            mg.InstanceExpression = new FieldExpr(builder, Location);

            var param_reference = block.GetParameterReference(0, Location);

            param_reference.Type   = istate_machine.TypeSpec;
            param_reference.eclass = ExprClass.Variable;

            var args = new Arguments(1);

            args.Add(new Argument(param_reference));
            set_state_machine.Block.AddStatement(new StatementExpression(new Invocation(mg, args)));

            if (has_task_return_type)
            {
                HoistedReturnValue = TemporaryVariableReference.Create(bt.TypeArguments [0], StateMachineMethod.Block, Location);
            }

            return(true);
        }
示例#10
0
文件: async.cs 项目: raj581/Marvin
        protected override bool DoDefineMembers()
        {
            var action = Module.PredefinedTypes.Action.Resolve();

            if (action != null)
            {
                continuation           = AddCompilerGeneratedField("$continuation", new TypeExpression(action, Location), true);
                continuation.ModFlags |= Modifiers.READONLY;
            }

            PredefinedType builder_type;
            PredefinedMember <MethodSpec> bf;
            PredefinedMember <MethodSpec> sr;
            PredefinedMember <MethodSpec> se;
            bool has_task_return_type = false;
            var  pred_members         = Module.PredefinedMembers;

            if (return_type.Kind == MemberKind.Void)
            {
                builder_type = Module.PredefinedTypes.AsyncVoidMethodBuilder;
                bf           = pred_members.AsyncVoidMethodBuilderCreate;
                sr           = pred_members.AsyncVoidMethodBuilderSetResult;
                se           = pred_members.AsyncVoidMethodBuilderSetException;
            }
            else if (return_type == Module.PredefinedTypes.Task.TypeSpec)
            {
                builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilder;
                bf           = pred_members.AsyncTaskMethodBuilderCreate;
                sr           = pred_members.AsyncTaskMethodBuilderSetResult;
                se           = pred_members.AsyncTaskMethodBuilderSetException;
                task         = pred_members.AsyncTaskMethodBuilderTask.Get();
            }
            else
            {
                builder_type         = Module.PredefinedTypes.AsyncTaskMethodBuilderGeneric;
                bf                   = pred_members.AsyncTaskMethodBuilderGenericCreate;
                sr                   = pred_members.AsyncTaskMethodBuilderGenericSetResult;
                se                   = pred_members.AsyncTaskMethodBuilderGenericSetException;
                task                 = pred_members.AsyncTaskMethodBuilderGenericTask.Get();
                has_task_return_type = true;
            }

            set_result    = sr.Get();
            set_exception = se.Get();
            var builder_factory = bf.Get();

            if (!builder_type.Define() || set_result == null || builder_factory == null || set_exception == null)
            {
                Report.Error(1993, Location,
                             "Cannot find compiler required types for asynchronous functions support. Are you targeting the wrong framework version?");
                return(base.DoDefineMembers());
            }

            var bt = builder_type.TypeSpec;

            //
            // Inflate generic Task types
            //
            if (has_task_return_type)
            {
                var task_return_type = return_type.TypeArguments;
                if (mutator != null)
                {
                    task_return_type = mutator.Mutate(task_return_type);
                }

                bt = bt.MakeGenericType(Module, task_return_type);
                builder_factory = MemberCache.GetMember <MethodSpec> (bt, builder_factory);
                set_result      = MemberCache.GetMember <MethodSpec> (bt, set_result);
                set_exception   = MemberCache.GetMember <MethodSpec> (bt, set_exception);

                if (task != null)
                {
                    task = MemberCache.GetMember <PropertySpec> (bt, task);
                }
            }

            builder = AddCompilerGeneratedField("$builder", new TypeExpression(bt, Location));

            if (!base.DoDefineMembers())
            {
                return(false);
            }

            MethodGroupExpr mg;
            var             block = instance_constructors[0].Block;

            //
            // Initialize continuation with state machine method
            //
            if (continuation != null)
            {
                var args = new Arguments(1);
                mg = MethodGroupExpr.CreatePredefined(StateMachineMethod.Spec, spec, Location);
                args.Add(new Argument(mg));

                block.AddStatement(
                    new StatementExpression(new SimpleAssign(
                                                new FieldExpr(continuation, Location),
                                                new NewDelegate(action, args, Location),
                                                Location
                                                )));
            }

            mg = MethodGroupExpr.CreatePredefined(builder_factory, bt, Location);
            block.AddStatement(
                new StatementExpression(new SimpleAssign(
                                            new FieldExpr(builder, Location),
                                            new Invocation(mg, new Arguments(0)),
                                            Location)));

            if (has_task_return_type)
            {
                hoisted_return = LocalVariable.CreateCompilerGenerated(bt.TypeArguments[0], block, Location);
            }

            return(true);
        }
示例#11
0
文件: async.cs 项目: raj581/Marvin
        public void EmitPrologue(EmitContext ec)
        {
            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);

            Label skip_continuation = ec.DefineLabel();

            Expression completed_expr;

            if (IsDynamic)
            {
                var rc = new ResolveContext(ec.MemberContext);

                Arguments dargs = new Arguments(1);
                dargs.Add(new Argument(fe_awaiter));
                completed_expr = new DynamicMemberBinder("IsCompleted", dargs, loc).Resolve(rc);
            }
            else
            {
                var pe = PropertyExpr.CreatePredefined(is_completed, loc);
                pe.InstanceExpression = fe_awaiter;
                completed_expr        = pe;
            }

            completed_expr.EmitBranchable(ec, skip_continuation, true);

            base.DoEmit(ec);

            //
            // The stack has to be empty before calling await continuation. We handle this
            // by lifting values which would be left on stack into class fields. The process
            // is quite complicated and quite hard to test because any expression can possibly
            // leave a value on the stack.
            //
            // Following assert fails when some of expression called before is missing EmitToField
            // or parent expression fails to find await in children expressions
            //
            ec.AssertEmptyStack();

            var args    = new Arguments(1);
            var storey  = (AsyncTaskStorey)machine_initializer.Storey;
            var fe_cont = new FieldExpr(storey.Continuation, loc);

            fe_cont.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            args.Add(new Argument(fe_cont));

            if (IsDynamic)
            {
                var rc      = new ResolveContext(ec.MemberContext);
                var mg_expr = new Invocation(new MemberAccess(fe_awaiter, "OnCompleted"), args).Resolve(rc);

                ExpressionStatement es = (ExpressionStatement)mg_expr;
                es.EmitStatement(ec);
            }
            else
            {
                var mg_completed = MethodGroupExpr.CreatePredefined(on_completed, fe_awaiter.Type, loc);
                mg_completed.InstanceExpression = fe_awaiter;

                //
                // awaiter.OnCompleted (continuation);
                //
                mg_completed.EmitCall(ec, args);
            }

            // Return ok
            machine_initializer.EmitLeave(ec, unwind_protect);

            ec.MarkLabel(resume_point);
            ec.MarkLabel(skip_continuation);
        }
示例#12
0
文件: async.cs 项目: allisterb/Escher
        void EmitOnCompleted(EmitContext ec, Expression awaiter, bool unsafeVersion)
        {
            var pm = Module.PredefinedMembers;
            PredefinedMember <MethodSpec> predefined;
            bool has_task_return_type = false;

            if (return_type.Kind == MemberKind.Void)
            {
                predefined = unsafeVersion ? pm.AsyncVoidMethodBuilderOnCompletedUnsafe : pm.AsyncVoidMethodBuilderOnCompleted;
            }
            else if (return_type == Module.PredefinedTypes.Task.TypeSpec)
            {
                predefined = unsafeVersion ? pm.AsyncTaskMethodBuilderOnCompletedUnsafe : pm.AsyncTaskMethodBuilderOnCompleted;
            }
            else if (return_type.IsGenericTask)
            {
                predefined           = unsafeVersion ? pm.AsyncTaskMethodBuilderGenericOnCompletedUnsafe : pm.AsyncTaskMethodBuilderGenericOnCompleted;
                has_task_return_type = true;
            }
            else
            {
                var parameters = new ParametersImported(
                    new [] {
                    new ParameterData(null, Parameter.Modifier.REF),
                    new ParameterData(null, Parameter.Modifier.REF)
                },
                    new [] {
                    new TypeParameterSpec(0, null, SpecialConstraint.None, Variance.None, null),
                    new TypeParameterSpec(1, null, SpecialConstraint.None, Variance.None, null)
                }, false);

                var on_completed_sign = unsafeVersion ?
                                        MemberFilter.Method("AwaitUnsafeOnCompleted", 2, parameters, Compiler.BuiltinTypes.Void) :
                                        MemberFilter.Method("AwaitOnCompleted", 2, parameters, Compiler.BuiltinTypes.Void);

                predefined           = new PredefinedMember <MethodSpec> (Module, return_type.MemberDefinition.GetAsyncMethodBuilder(), on_completed_sign);
                has_task_return_type = return_type.IsGeneric;
            }

            var on_completed = predefined.Resolve(Location);

            if (on_completed == null)
            {
                return;
            }

            if (has_task_return_type)
            {
                on_completed = MemberCache.GetMember <MethodSpec> (set_result.DeclaringType, on_completed);
            }

            on_completed = on_completed.MakeGenericMethod(this, awaiter.Type, ec.CurrentType);

            var mg = MethodGroupExpr.CreatePredefined(on_completed, on_completed.DeclaringType, Location);

            mg.InstanceExpression = new FieldExpr(builder, Location)
            {
                InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, Location)
            };

            var args = new Arguments(2);

            args.Add(new Argument(awaiter, Argument.AType.Ref));
            args.Add(new Argument(new CompilerGeneratedThis(CurrentType, Location), Argument.AType.Ref));
            using (ec.With(BuilderContext.Options.OmitDebugInfo, true)) {
                mg.EmitCall(ec, args, true);
            }
        }
示例#13
0
文件: async.cs 项目: allisterb/Escher
        protected override bool DoDefineMembers()
        {
            TypeSpec   bt;
            bool       has_task_return_type = false;
            var        istate_machine       = Module.PredefinedTypes.IAsyncStateMachine;
            MethodSpec set_statemachine;

            if (return_type.IsCustomTaskType())
            {
                //
                // TODO: Would be nice to cache all this on per-type basis
                //
                var btypes = Compiler.BuiltinTypes;
                bt = return_type.MemberDefinition.GetAsyncMethodBuilder();
                TypeSpec bt_inflated;
                if (return_type.IsGeneric)
                {
                    bt_inflated = bt.MakeGenericType(Module, bt.MemberDefinition.TypeParameters);
                }
                else
                {
                    bt_inflated = bt;
                }

                var set_result_sign = MemberFilter.Method("SetResult", 0, ParametersCompiled.CreateFullyResolved(bt.MemberDefinition.TypeParameters), btypes.Void);
                set_result = new PredefinedMember <MethodSpec> (Module, bt, set_result_sign).Resolve(Location);

                var set_exception_sign = MemberFilter.Method("SetException", 0, ParametersCompiled.CreateFullyResolved(btypes.Exception), btypes.Void);
                set_exception = new PredefinedMember <MethodSpec> (Module, bt, set_exception_sign).Resolve(Location);

                var builder_factory_sign = MemberFilter.Method("Create", 0, ParametersCompiled.EmptyReadOnlyParameters, bt_inflated);
                builder_factory = new PredefinedMember <MethodSpec> (Module, bt, builder_factory_sign).Resolve(Location);
                if (builder_factory?.IsStatic == false)
                {
                    throw new NotImplementedException("report better error message");
                }

                var builder_start_sign = MemberFilter.Method("Start", 1, new ParametersImported(
                                                                 new [] {
                    new ParameterData(null, Parameter.Modifier.REF),
                },
                                                                 new [] {
                    new TypeParameterSpec(0, null, SpecialConstraint.None, Variance.None, null),
                }, false),
                                                             btypes.Void);
                builder_start = new PredefinedMember <MethodSpec> (Module, bt, builder_start_sign).Resolve(Location);

                if (!istate_machine.Define())
                {
                    return(false);
                }

                var set_statemachine_sign = MemberFilter.Method("SetStateMachine", 0, ParametersCompiled.CreateFullyResolved(istate_machine.TypeSpec), btypes.Void);
                set_statemachine = new PredefinedMember <MethodSpec> (Module, bt, set_statemachine_sign).Resolve(Location);;

                var task_sign = MemberFilter.Property("Task", return_type.MemberDefinition as TypeSpec);
                task = new PredefinedMember <PropertySpec> (Module, bt, task_sign).Resolve(Location);

                if (set_result == null || set_exception == null || builder_factory == null || builder_start == null || set_statemachine == null || task == null ||
                    !Module.PredefinedTypes.INotifyCompletion.Define())
                {
                    return(false);
                }

                has_task_return_type = return_type.IsGeneric;
            }
            else
            {
                PredefinedType builder_type;
                PredefinedMember <MethodSpec> bf;
                PredefinedMember <MethodSpec> bs;
                PredefinedMember <MethodSpec> sr;
                PredefinedMember <MethodSpec> se;
                PredefinedMember <MethodSpec> sm;
                var pred_members = Module.PredefinedMembers;

                if (return_type.Kind == MemberKind.Void)
                {
                    builder_type = Module.PredefinedTypes.AsyncVoidMethodBuilder;
                    bf           = pred_members.AsyncVoidMethodBuilderCreate;
                    bs           = pred_members.AsyncVoidMethodBuilderStart;
                    sr           = pred_members.AsyncVoidMethodBuilderSetResult;
                    se           = pred_members.AsyncVoidMethodBuilderSetException;
                    sm           = pred_members.AsyncVoidMethodBuilderSetStateMachine;
                }
                else if (return_type == Module.PredefinedTypes.Task.TypeSpec)
                {
                    builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilder;
                    bf           = pred_members.AsyncTaskMethodBuilderCreate;
                    bs           = pred_members.AsyncTaskMethodBuilderStart;
                    sr           = pred_members.AsyncTaskMethodBuilderSetResult;
                    se           = pred_members.AsyncTaskMethodBuilderSetException;
                    sm           = pred_members.AsyncTaskMethodBuilderSetStateMachine;
                    task         = pred_members.AsyncTaskMethodBuilderTask.Get();
                }
                else
                {
                    builder_type         = Module.PredefinedTypes.AsyncTaskMethodBuilderGeneric;
                    bf                   = pred_members.AsyncTaskMethodBuilderGenericCreate;
                    bs                   = pred_members.AsyncTaskMethodBuilderGenericStart;
                    sr                   = pred_members.AsyncTaskMethodBuilderGenericSetResult;
                    se                   = pred_members.AsyncTaskMethodBuilderGenericSetException;
                    sm                   = pred_members.AsyncTaskMethodBuilderGenericSetStateMachine;
                    task                 = pred_members.AsyncTaskMethodBuilderGenericTask.Get();
                    has_task_return_type = true;
                }

                set_result      = sr.Get();
                set_exception   = se.Get();
                builder_factory = bf.Get();
                builder_start   = bs.Get();

                set_statemachine = sm.Get();

                if (!builder_type.Define() || !istate_machine.Define() || set_result == null || builder_factory == null ||
                    set_exception == null || set_statemachine == null || builder_start == null ||
                    !Module.PredefinedTypes.INotifyCompletion.Define())
                {
                    Report.Error(1993, Location,
                                 "Cannot find compiler required types for asynchronous functions support. Are you targeting the wrong framework version?");
                    return(base.DoDefineMembers());
                }

                bt = builder_type.TypeSpec;
            }

            //
            // Inflate generic Task types
            //
            if (has_task_return_type)
            {
                var task_return_type = return_type.TypeArguments;
                if (mutator != null)
                {
                    task_return_type = mutator.Mutate(task_return_type);
                }

                bt               = bt.MakeGenericType(Module, task_return_type);
                set_result       = MemberCache.GetMember(bt, set_result);
                set_exception    = MemberCache.GetMember(bt, set_exception);
                set_statemachine = MemberCache.GetMember(bt, set_statemachine);

                if (task != null)
                {
                    task = MemberCache.GetMember(bt, task);
                }
            }

            builder = AddCompilerGeneratedField("$builder", new TypeExpression(bt, Location));

            Field rfield;

            if (has_task_return_type && HasAwaitInsideFinally)
            {
                //
                // Special case async block with return value from finally clause. In such case
                // we rewrite all return expresison stores to stfld to $return. Instead of treating
                // returns outside of finally and inside of finally differently.
                //
                rfield = AddCompilerGeneratedField("$return", new TypeExpression(bt.TypeArguments [0], Location));
            }
            else
            {
                rfield = null;
            }

            var set_state_machine = new Method(this, new TypeExpression(Compiler.BuiltinTypes.Void, Location),
                                               Modifiers.COMPILER_GENERATED | Modifiers.DEBUGGER_HIDDEN | Modifiers.PUBLIC,
                                               new MemberName("SetStateMachine"),
                                               ParametersCompiled.CreateFullyResolved(
                                                   new Parameter(new TypeExpression(istate_machine.TypeSpec, Location), "stateMachine", Parameter.Modifier.NONE, null, Location),
                                                   istate_machine.TypeSpec),
                                               null);

            ToplevelBlock block = new ToplevelBlock(Compiler, set_state_machine.ParameterInfo, Location);

            block.IsCompilerGenerated = true;
            set_state_machine.Block   = block;

            Members.Add(set_state_machine);

            if (!base.DoDefineMembers())
            {
                return(false);
            }

            //
            // Fabricates SetStateMachine method
            //
            // public void SetStateMachine (IAsyncStateMachine stateMachine)
            // {
            //    $builder.SetStateMachine (stateMachine);
            // }
            //
            var mg = MethodGroupExpr.CreatePredefined(set_statemachine, bt, Location);

            mg.InstanceExpression = new FieldExpr(builder, Location);

            var param_reference = block.GetParameterReference(0, Location);

            param_reference.Type   = istate_machine.TypeSpec;
            param_reference.eclass = ExprClass.Variable;

            var args = new Arguments(1);

            args.Add(new Argument(param_reference));
            set_state_machine.Block.AddStatement(new StatementExpression(new Invocation(mg, args)));

            if (has_task_return_type)
            {
                if (rfield != null)
                {
                    HoistedReturnValue = new FieldExpr(rfield, Location)
                    {
                        InstanceExpression = new CompilerGeneratedThis(CurrentType, Location.Null)
                    };
                }
                else
                {
                    HoistedReturnValue = TemporaryVariableReference.Create(bt.TypeArguments [0], StateMachineMethod.Block, Location);
                }
            }

            return(true);
        }
示例#14
0
        public void EmitPrologue(EmitContext ec)
        {
            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);

            Label skip_continuation = ec.DefineLabel();

            is_completed.InstanceExpression = fe_awaiter;
            is_completed.EmitBranchable(ec, skip_continuation, true);

            base.DoEmit(ec);

            FieldSpec[] stack_fields = null;
            TypeSpec[]  stack        = null;
            //
            // Here is the clever bit. We know that await statement has to yield the control
            // back but it can appear inside almost any expression. This means the stack can
            // contain any depth of values and same values have to be present when the continuation
            // handles control back.
            //
            // For example: await a + await b
            //
            // In this case we fabricate a static stack forwarding method which moves the values
            // from the stack to async storey fields. On re-entry point we restore exactly same
            // stack using these fields.
            //
            // We fabricate a static method because we don't want to touch original stack and
            // the instance method would require `this' as the first stack value on the stack
            //
            if (ec.StackHeight > 0)
            {
                var async_storey = (AsyncTaskStorey)machine_initializer.Storey;

                stack = ec.GetStackTypes();
                var method = async_storey.GetStackForwarder(stack, out stack_fields);
                ec.EmitThis();
                ec.Emit(OpCodes.Call, method);
            }

            var mg_completed = MethodGroupExpr.CreatePredefined(on_completed, fe_awaiter.Type, loc);

            mg_completed.InstanceExpression = fe_awaiter;

            var args    = new Arguments(1);
            var storey  = (AsyncTaskStorey)machine_initializer.Storey;
            var fe_cont = new FieldExpr(storey.Continuation, loc);

            fe_cont.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc);

            args.Add(new Argument(fe_cont));

            //
            // awaiter.OnCompleted (continuation);
            //
            mg_completed.EmitCall(ec, args);

            // Return ok
            machine_initializer.EmitLeave(ec, unwind_protect);

            ec.MarkLabel(resume_point);

            if (stack_fields != null)
            {
                for (int i = 0; i < stack_fields.Length; ++i)
                {
                    ec.EmitThis();

                    var field = stack_fields[i];

                    //
                    // We don't store `this' because it can be easily re-created
                    //
                    if (field == null)
                    {
                        continue;
                    }

                    if (stack[i] is ReferenceContainer)
                    {
                        ec.Emit(OpCodes.Ldflda, field);
                    }
                    else
                    {
                        ec.Emit(OpCodes.Ldfld, field);
                    }
                }
            }

            ec.MarkLabel(skip_continuation);
        }