/// <summary> /// Generate the body for <c>MoveNext()</c>. /// </summary> internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod) { F.CurrentMethod = moveNextMethod; int initialState; GeneratedLabelSymbol initialLabel; AddState(out initialState, out initialLabel); var exceptionLocal = F.SynthesizedLocal(F.WellKnownType(WellKnownType.System_Exception), GeneratedNames.AsyncExceptionFieldName()); var bodyBuilder = ArrayBuilder <BoundStatement> .GetInstance(); bodyBuilder.Add( F.HiddenSequencePoint()); bodyBuilder.Add( F.Assignment(F.Local(cachedState), F.Field(F.This(), stateField))); BoundStatement rewrittenBody = (BoundStatement)Visit(body); bodyBuilder.Add( F.Try( F.Block( ImmutableArray <LocalSymbol> .Empty, // switch (state) ... F.HiddenSequencePoint(), Dispatch(), F.Label(initialLabel), // [body] rewrittenBody ), F.CatchBlocks( F.Catch( exceptionLocal, F.Block( F.NoOp(method.ReturnsVoid ? NoOpStatementFlavor.AsyncMethodCatchHandler : NoOpStatementFlavor.Default), F.HiddenSequencePoint(), // this.state = finishedState F.Assignment(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FinishedStateMachine)), // builder.SetException(ex) F.ExpressionStatement( F.Call( F.Field(F.This(), asyncMethodBuilderField), asyncMethodBuilderMemberCollection.SetException, F.Local(exceptionLocal))), GenerateReturn(false) ) ) ) )); // ReturnLabel (for the rewritten return expressions in the user's method body) bodyBuilder.Add(F.Label(exprReturnLabel)); // this.state = finishedState var stateDone = F.Assignment(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FinishedStateMachine)); var block = body.Syntax as BlockSyntax; if (block == null) { // this happens, for example, in (async () => await e) where there is no block syntax bodyBuilder.Add(stateDone); } else { bodyBuilder.Add(F.SequencePointWithSpan(block, block.CloseBraceToken.Span, stateDone)); bodyBuilder.Add(F.HiddenSequencePoint()); // The remaining code is hidden to hide the fact that it can run concurrently with the task's continuation } // builder.SetResult([RetVal]) bodyBuilder.Add( F.ExpressionStatement( F.Call( F.Field(F.This(), asyncMethodBuilderField), asyncMethodBuilderMemberCollection.SetResult, method.IsGenericTaskReturningAsync(F.Compilation) ? ImmutableArray.Create <BoundExpression>(F.Local(exprRetValue)) : ImmutableArray <BoundExpression> .Empty))); // this code is hidden behind a hidden sequence point. bodyBuilder.Add(F.Label(this.exitLabel)); bodyBuilder.Add(F.Return()); var newBody = bodyBuilder.ToImmutableAndFree(); var locals = ArrayBuilder <LocalSymbol> .GetInstance(); locals.Add(cachedState); if ((object)exprRetValue != null) { locals.Add(exprRetValue); } F.CloseMethod( F.SequencePoint( body.Syntax, F.Block( locals.ToImmutableAndFree(), newBody))); }
/// <summary> /// Generate the body for MoveNext() /// </summary> internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod) { F.CurrentMethod = moveNextMethod; int initialState; GeneratedLabelSymbol initialLabel; AddState(out initialState, out initialLabel); var exceptionLocal = F.SynthesizedLocal(F.WellKnownType(WellKnownType.System_Exception), GeneratedNames.AsyncExceptionFieldName()); BoundStatement rewrittenBody = (BoundStatement)Visit(body); rewrittenBody = (BoundStatement) new AwaitLoweringRewriterPass1(F).Visit(rewrittenBody); rewrittenBody = (BoundStatement) new AwaitLoweringRewriterPass2(F, CompilationState).Visit(rewrittenBody); UnloweredSpillNodeVerifier.Verify(rewrittenBody); var bodyBuilder = ArrayBuilder <BoundStatement> .GetInstance(); bodyBuilder.Add( F.Try( F.Block( ReadOnlyArray <LocalSymbol> .Empty, // switch (state) ... Dispatch(), // TODO(t-liam) - debugging support... // dev11(LanguageAnalysis\Compiler\ResumableRewriter.cpp:325) does codegen here to add a // debug nop and the 'NoCullNormalExit' label F.Label(initialLabel), // [body] rewrittenBody ), F.CatchBlocks( // TODO(t-liam) - debugging support... // dev11(LanguageAnalysis\Compiler\ResumableRewriter.cpp:391) // // Async void method generated catch handlers have their IL start offset // // recorded to the PDB for special exception handling in the debugger. // // Mark the EXPRHANDLER as such so we know to record its offset later. F.Catch( F.WellKnownType(WellKnownType.System_Exception), exceptionLocal, F.Block( // state = finishedState F.Assignment(F.Field(F.This(), state), F.Literal(StateMachineStates.FinishedStateMachine)), // builder.SetException(ex) F.ExpressionStatement( F.Call( F.Field(F.This(), asyncMethodBuilderField), asyncMethodBuilderMemberCollection.SetException, ReadOnlyArray <BoundExpression> .CreateFrom(F.Local(exceptionLocal)))), F.Return() ) ) ) )); // ReturnLabel (for the rewritten return expressions in the user's method body) bodyBuilder.Add(F.Label(exprReturnLabel)); // state = finishedState bodyBuilder.Add(F.Assignment(F.Field(F.This(), state), F.Literal(StateMachineStates.FinishedStateMachine))); // builder.SetResult([RetVal]) bodyBuilder.Add( F.ExpressionStatement( F.Call( F.Field(F.This(), asyncMethodBuilderField), asyncMethodBuilderMemberCollection.SetResult, method.IsGenericTaskReturningAsync() ? ReadOnlyArray <BoundExpression> .CreateFrom(F.Local(exprRetValue)) : ReadOnlyArray <BoundExpression> .Empty))); bodyBuilder.Add(F.Return()); var newBody = bodyBuilder.ToReadOnlyAndFree(); F.CloseMethod( F.SequencePoint( body.Syntax, F.Block( exprRetValue != null ? ReadOnlyArray <LocalSymbol> .CreateFrom(exprRetValue) : ReadOnlyArray <LocalSymbol> .Empty, newBody))); }