public void EmitPrologue(EmitContext ec) { awaiter = ((AsyncTaskStorey)machine_initializer.Storey).AddAwaiter(expr.Type); var fe_awaiter = new FieldExpr(awaiter, loc); fe_awaiter.InstanceExpression = new CompilerGeneratedThis(ec.CurrentType, loc); Label skip_continuation = ec.DefineLabel(); using (ec.With(BuilderContext.Options.OmitDebugInfo, true)) { // // awaiter = expr.GetAwaiter (); // fe_awaiter.EmitAssign(ec, expr, false, false); 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); dargs = new Arguments(1); dargs.Add(new Argument(completed_expr)); completed_expr = new DynamicConversion(ec.Module.Compiler.BuiltinTypes.Bool, 0, dargs, loc).Resolve(rc); } else { var pe = PropertyExpr.CreatePredefined(awaiter_definition.IsCompleted, 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 storey = (AsyncTaskStorey)machine_initializer.Storey; if (IsDynamic) { storey.EmitAwaitOnCompletedDynamic(ec, fe_awaiter); } else { storey.EmitAwaitOnCompleted(ec, fe_awaiter); } // Return ok machine_initializer.EmitLeave(ec, unwind_protect); ec.MarkLabel(resume_point); ec.MarkLabel(skip_continuation); }
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); }