예제 #1
0
파일: async.cs 프로젝트: z3nth10n/ILSpy-CMD
        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);
            }
        }
예제 #2
0
		public FieldSpec Mutate (TypeParameterMutator mutator)
		{
			var decl = DeclaringType;
			if (DeclaringType.IsGenericOrParentIsGeneric)
				decl = mutator.Mutate (decl);

			if (decl == DeclaringType)
				return this;

			var fs = (FieldSpec) MemberwiseClone ();
			fs.declaringType = decl;
			fs.state |= StateFlags.PendingMetaInflate;

			// Gets back FieldInfo in case of metaInfo was inflated
			fs.metaInfo = MemberCache.GetMember (TypeParameterMutator.GetMemberDeclaringType (DeclaringType), this).metaInfo;
			return fs;
		}
예제 #3
0
파일: async.cs 프로젝트: raj581/Marvin
        public override void EmitStatement(EmitContext ec)
        {
            var storey = (AsyncTaskStorey)Storey;

            storey.Instance.Emit(ec);

            var move_next_entry = storey.StateMachineMethod.Spec;

            if (storey.MemberName.Arity > 0)
            {
                move_next_entry = MemberCache.GetMember(storey.Instance.Type, move_next_entry);
            }

            ec.Emit(OpCodes.Call, move_next_entry);

            //
            // Emits return <async-storey-instance>.$builder.Task;
            //
            if (storey.Task != null)
            {
                var builder_field = storey.Builder.Spec;
                var task_get      = storey.Task.Get;

                if (storey.MemberName.Arity > 0)
                {
                    builder_field = MemberCache.GetMember(storey.Instance.Type, builder_field);
                    task_get      = MemberCache.GetMember(builder_field.MemberType, task_get);
                }

                var pe_task = new PropertyExpr(storey.Task, loc)
                {
                    InstanceExpression = new FieldExpr(builder_field, loc)
                    {
                        InstanceExpression = storey.Instance
                    },
                    Getter = task_get
                };

                pe_task.Emit(ec);
            }

            ec.Emit(OpCodes.Ret);
        }
예제 #4
0
파일: iterators.cs 프로젝트: nuxleus/mono
        public override void Emit(EmitContext ec)
        {
            //
            // Load Iterator storey instance
            //
            IteratorHost.Instance.Emit(ec);

            //
            // Initialize iterator PC when it's unitialized
            //
            if (IsEnumerable)
            {
                ec.Emit(OpCodes.Dup);
                ec.EmitInt((int)State.Uninitialized);

                var field = IteratorHost.PC.Spec;
                if (Storey.MemberName.IsGeneric)
                {
                    field = MemberCache.GetMember(Storey.Instance.Type, field);
                }

                ec.Emit(OpCodes.Stfld, field);
            }
        }
예제 #5
0
파일: async.cs 프로젝트: xiaotie/NRefactory
        public void EmitInitializer(EmitContext ec)
        {
            //
            // Some predefined types are missing
            //
            if (builder == null)
            {
                return;
            }

            var instance      = (TemporaryVariableReference)Instance;
            var builder_field = builder.Spec;

            if (MemberName.Arity > 0)
            {
                builder_field = MemberCache.GetMember(instance.Type, builder_field);
            }

            //
            // Inflated factory method when task is of generic type
            //
            if (builder_factory.DeclaringType.IsGeneric)
            {
                var task_return_type = return_type.TypeArguments;
                var bt = builder_factory.DeclaringType.MakeGenericType(Module, task_return_type);
                builder_factory = MemberCache.GetMember(bt, builder_factory);
                builder_start   = MemberCache.GetMember(bt, builder_start);
            }

            //
            // stateMachine.$builder = AsyncTaskMethodBuilder<{task-type}>.Create();
            //
            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.AddressOf(ec, AddressOp.Store);
            ec.Emit(OpCodes.Ldflda, builder_field);
            if (Task != null)
            {
                ec.Emit(OpCodes.Dup);
            }
            instance.AddressOf(ec, AddressOp.Store);
            ec.Emit(OpCodes.Call, builder_start.MakeGenericMethod(Module, instance.Type));

            //
            // Emits return stateMachine.$builder.Task;
            //
            if (Task != null)
            {
                var task_get = Task.Get;

                if (MemberName.Arity > 0)
                {
                    task_get = MemberCache.GetMember(builder_field.MemberType, task_get);
                }

                var pe_task = new PropertyExpr(Task, Location)
                {
                    InstanceExpression = EmptyExpression.Null,    // Comes from the dup above
                    Getter             = task_get
                };

                pe_task.Emit(ec);
            }
        }
예제 #6
0
파일: async.cs 프로젝트: xiaotie/NRefactory
        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);
        }
예제 #7
0
        protected void EmitCall(EmitContext ec, Expression binder, Arguments arguments, bool isStatement)
        {
            //
            // This method generates all internal infrastructure for a dynamic call. The
            // reason why it's quite complicated is the mixture of dynamic and anonymous
            // methods. Dynamic itself requires a temporary class (ContainerX) and anonymous
            // methods can generate temporary storey as well (AnonStorey). Handling MVAR
            // type parameters rewrite is non-trivial in such case as there are various
            // combinations possible therefore the mutator is not straightforward. Secondly
            // we need to keep both MVAR(possibly VAR for anon storey) and type VAR to emit
            // correct Site field type and its access from EmitContext.
            //

            int dyn_args_count = arguments == null ? 0 : arguments.Count;
            int default_args   = isStatement ? 1 : 2;
            var module         = ec.Module;

            bool has_ref_out_argument = false;
            var  targs = new TypeExpression[dyn_args_count + default_args];

            targs[0] = new TypeExpression(module.PredefinedTypes.CallSite.TypeSpec, loc);

            TypeExpression[]     targs_for_instance = null;
            TypeParameterMutator mutator;

            var site_container = ec.CreateDynamicSite();

            if (context_mvars != null)
            {
                TypeParameters tparam;
                TypeContainer  sc = site_container;
                do
                {
                    tparam = sc.CurrentTypeParameters;
                    sc     = sc.Parent;
                } while (tparam == null);

                mutator = new TypeParameterMutator(context_mvars, tparam);

                if (!ec.IsAnonymousStoreyMutateRequired)
                {
                    targs_for_instance    = new TypeExpression[targs.Length];
                    targs_for_instance[0] = targs[0];
                }
            }
            else
            {
                mutator = null;
            }

            for (int i = 0; i < dyn_args_count; ++i)
            {
                Argument a = arguments[i];
                if (a.ArgType == Argument.AType.Out || a.ArgType == Argument.AType.Ref)
                {
                    has_ref_out_argument = true;
                }

                var t = a.Type;

                // Convert any internal type like dynamic or null to object
                if (t.Kind == MemberKind.InternalCompilerType)
                {
                    t = ec.BuiltinTypes.Object;
                }

                if (targs_for_instance != null)
                {
                    targs_for_instance[i + 1] = new TypeExpression(t, loc);
                }

                if (mutator != null)
                {
                    t = t.Mutate(mutator);
                }

                targs[i + 1] = new TypeExpression(t, loc);
            }

            TypeExpr del_type = null;
            TypeExpr del_type_instance_access = null;

            if (!has_ref_out_argument)
            {
                string d_name = isStatement ? "Action" : "Func";

                TypeSpec  te      = null;
                Namespace type_ns = module.GlobalRootNamespace.GetNamespace("System", true);
                if (type_ns != null)
                {
                    te = type_ns.LookupType(module, d_name, dyn_args_count + default_args, LookupMode.Normal, loc);
                }

                if (te != null)
                {
                    if (!isStatement)
                    {
                        var t = type;
                        if (t.Kind == MemberKind.InternalCompilerType)
                        {
                            t = ec.BuiltinTypes.Object;
                        }

                        if (targs_for_instance != null)
                        {
                            targs_for_instance[targs_for_instance.Length - 1] = new TypeExpression(t, loc);
                        }

                        if (mutator != null)
                        {
                            t = t.Mutate(mutator);
                        }

                        targs[targs.Length - 1] = new TypeExpression(t, loc);
                    }

                    del_type = new GenericTypeExpr(te, new TypeArguments(targs), loc);
                    if (targs_for_instance != null)
                    {
                        del_type_instance_access = new GenericTypeExpr(te, new TypeArguments(targs_for_instance), loc);
                    }
                    else
                    {
                        del_type_instance_access = del_type;
                    }
                }
            }

            //
            // Create custom delegate when no appropriate predefined delegate has been found
            //
            Delegate d;

            if (del_type == null)
            {
                TypeSpec    rt = isStatement ? ec.BuiltinTypes.Void : type;
                Parameter[] p  = new Parameter[dyn_args_count + 1];
                p[0] = new Parameter(targs[0], "p0", Parameter.Modifier.NONE, null, loc);

                var site  = ec.CreateDynamicSite();
                int index = site.Containers == null ? 0 : site.Containers.Count;

                if (mutator != null)
                {
                    rt = mutator.Mutate(rt);
                }

                for (int i = 1; i < dyn_args_count + 1; ++i)
                {
                    p[i] = new Parameter(targs[i], "p" + i.ToString("X"), arguments[i - 1].Modifier, null, loc);
                }

                d = new Delegate(site, new TypeExpression(rt, loc),
                                 Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED,
                                 new MemberName("Container" + index.ToString("X")),
                                 new ParametersCompiled(p), null);

                d.CreateContainer();
                d.DefineContainer();
                d.Define();
                d.PrepareEmit();

                site.AddTypeContainer(d);

                //
                // Add new container to inflated site container when the
                // member cache already exists
                //
                if (site.CurrentType is InflatedTypeSpec && index > 0)
                {
                    site.CurrentType.MemberCache.AddMember(d.CurrentType);
                }

                del_type = new TypeExpression(d.CurrentType, loc);
                if (targs_for_instance != null)
                {
                    del_type_instance_access = null;
                }
                else
                {
                    del_type_instance_access = del_type;
                }
            }
            else
            {
                d = null;
            }

            var site_type_decl = new GenericTypeExpr(module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments(del_type), loc);
            var field          = site_container.CreateCallSiteField(site_type_decl, loc);

            if (field == null)
            {
                return;
            }

            if (del_type_instance_access == null)
            {
                var dt = d.CurrentType.DeclaringType.MakeGenericType(module, context_mvars.Types);
                del_type_instance_access = new TypeExpression(MemberCache.GetMember(dt, d.CurrentType), loc);
            }

            var instanceAccessExprType = new GenericTypeExpr(module.PredefinedTypes.CallSiteGeneric.TypeSpec,
                                                             new TypeArguments(del_type_instance_access), loc);

            if (instanceAccessExprType.ResolveAsType(ec.MemberContext) == null)
            {
                return;
            }

            bool inflate_using_mvar = context_mvars != null && ec.IsAnonymousStoreyMutateRequired;

            TypeSpec gt;

            if (inflate_using_mvar || context_mvars == null)
            {
                gt = site_container.CurrentType;
            }
            else
            {
                gt = site_container.CurrentType.MakeGenericType(module, context_mvars.Types);
            }

            // When site container already exists the inflated version has to be
            // updated manually to contain newly created field
            if (gt is InflatedTypeSpec && site_container.AnonymousMethodsCounter > 1)
            {
                var tparams  = gt.MemberDefinition.TypeParametersCount > 0 ? gt.MemberDefinition.TypeParameters : TypeParameterSpec.EmptyTypes;
                var inflator = new TypeParameterInflator(module, gt, tparams, gt.TypeArguments);
                gt.MemberCache.AddMember(field.InflateMember(inflator));
            }

            FieldExpr site_field_expr = new FieldExpr(MemberCache.GetMember(gt, field), loc);

            BlockContext bc = new BlockContext(ec.MemberContext, null, ec.BuiltinTypes.Void);

            Arguments args = new Arguments(1);

            args.Add(new Argument(binder));
            StatementExpression s = new StatementExpression(new SimpleAssign(site_field_expr, new Invocation(new MemberAccess(instanceAccessExprType, "Create"), args)));

            using (ec.With(BuilderContext.Options.OmitDebugInfo, true)) {
                if (s.Resolve(bc))
                {
                    Statement init = new If(new Binary(Binary.Operator.Equality, site_field_expr, new NullLiteral(loc)), s, loc);
                    init.Emit(ec);
                }

                args = new Arguments(1 + dyn_args_count);
                args.Add(new Argument(site_field_expr));
                if (arguments != null)
                {
                    int arg_pos = 1;
                    foreach (Argument a in arguments)
                    {
                        if (a is NamedArgument)
                        {
                            // Name is not valid in this context
                            args.Add(new Argument(a.Expr, a.ArgType));
                        }
                        else
                        {
                            args.Add(a);
                        }

                        if (inflate_using_mvar && a.Type != targs[arg_pos].Type)
                        {
                            a.Expr.Type = targs[arg_pos].Type;
                        }

                        ++arg_pos;
                    }
                }

                Expression target = new DelegateInvocation(new MemberAccess(site_field_expr, "Target", loc).Resolve(bc), args, loc).Resolve(bc);
                if (target != null)
                {
                    target.Emit(ec);
                }
            }
        }
예제 #8
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);
        }
예제 #9
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);
            }
        }
예제 #10
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);
        }