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