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); } }
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); }
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); }
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); } }
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)); }
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)); }
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); }
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))); }
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); }
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); }
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); }
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); } }
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); }
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); }