protected override void SetupStateMachine() { _stateMachineClass.AddBaseType(TypeSystemServices.ValueTypeType); _stateMachineClass.AddBaseType(TypeSystemServices.IAsyncStateMachineType); _stateMachineClass.Modifiers |= TypeMemberModifiers.Final; var ctr = TypeSystemServices.Map(typeof(AsyncStateMachineAttribute)).GetConstructors().Single(); _method.Method.Attributes.Add( CodeBuilder.CreateAttribute( ctr, CodeBuilder.CreateTypeofExpression(_stateMachineClass.Entity))); AsyncMethodBuilderMemberCollection.TryCreate( TypeSystemServices, _method.Method, MethodGenArg(true), out _asyncMethodBuilderMemberCollection); _state = (IField)_stateMachineClass.AddInternalField(UniqueName("State"), TypeSystemServices.IntType).Entity; _asyncMethodBuilderField = _stateMachineClass.AddInternalField( UniqueName("Builder"), _asyncMethodBuilderMemberCollection.BuilderType); CreateSetStateMachine(); PreprocessMethod(); }
private void FixAsyncMethodBody(MethodInvocationExpression stateMachineConstructorInvocation) { var method = _method.Method; // If the async method's result type is a type parameter of the method, then the AsyncTaskMethodBuilder<T> // needs to use the method's type parameters inside the rewritten method body. All other methods generated // during async rewriting are members of the synthesized state machine struct, and use the type parameters // structs type parameters. AsyncMethodBuilderMemberCollection methodScopeAsyncMethodBuilderMemberCollection; if (!AsyncMethodBuilderMemberCollection.TryCreate( TypeSystemServices, method, MethodGenArg(false), out methodScopeAsyncMethodBuilderMemberCollection)) { throw new NotImplementedException("Custom async patterns are not supported"); } var bodyBuilder = new Block(); var builderVariable = CodeBuilder.DeclareTempLocal(method, methodScopeAsyncMethodBuilderMemberCollection.BuilderType); var stateMachineType = stateMachineConstructorInvocation.ExpressionType; var stateMachineVariable = CodeBuilder.DeclareLocal( method, UniqueName("async"), stateMachineType); bodyBuilder.Add(CodeBuilder.CreateAssignment( CodeBuilder.CreateLocalReference(stateMachineVariable), stateMachineConstructorInvocation)); // local.$builder = System.Runtime.CompilerServices.AsyncTaskMethodBuilder<typeArgs>.Create(); bodyBuilder.Add( CodeBuilder.CreateAssignment( CodeBuilder.CreateMemberReference( CodeBuilder.CreateLocalReference(stateMachineVariable), ExternalFieldEntity((IField)_asyncMethodBuilderField.Entity, stateMachineType)), CodeBuilder.CreateMethodInvocation(methodScopeAsyncMethodBuilderMemberCollection.CreateBuilder))); // local.$stateField = NotStartedStateMachine bodyBuilder.Add( CodeBuilder.CreateAssignment( CodeBuilder.CreateMemberReference( CodeBuilder.CreateLocalReference(stateMachineVariable), ExternalFieldEntity(_state, stateMachineType)), CodeBuilder.CreateIntegerLiteral(StateMachineStates.NotStartedStateMachine))); bodyBuilder.Add( CodeBuilder.CreateAssignment( CodeBuilder.CreateLocalReference(builderVariable), CodeBuilder.CreateMemberReference( CodeBuilder.CreateLocalReference(stateMachineVariable), ExternalFieldEntity((IField)_asyncMethodBuilderField.Entity, stateMachineType)))); // local.$builder.Start(ref local) -- binding to the method AsyncTaskMethodBuilder<typeArgs>.Start() bodyBuilder.Add( CodeBuilder.CreateMethodInvocation( CodeBuilder.CreateLocalReference(builderVariable), methodScopeAsyncMethodBuilderMemberCollection.Start.GenericInfo.ConstructMethod(stateMachineType), CodeBuilder.CreateLocalReference(stateMachineVariable))); var methodBuilderField = stateMachineType.ConstructedInfo == null ? (IField)_asyncMethodBuilderField.Entity : stateMachineType.ConstructedInfo.Map((IField)_asyncMethodBuilderField.Entity); bodyBuilder.Add(method.ReturnType.Entity == TypeSystemServices.VoidType ? new ReturnStatement() : new ReturnStatement( CodeBuilder.CreateMethodInvocation( CodeBuilder.CreateMemberReference( CodeBuilder.CreateLocalReference(stateMachineVariable), methodBuilderField), methodScopeAsyncMethodBuilderMemberCollection.Task.GetGetMethod()))); _method.Method.Body = bodyBuilder; }