private BoundStatement RewriteWhileStatement( BoundLoopStatement loop, BoundExpression rewrittenCondition, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { Debug.Assert(loop.Kind == BoundKind.WhileStatement || loop.Kind == BoundKind.ForEachStatement); // while (condition) // body; // // becomes // // goto continue; // start: // { // body // continue: // GotoIfTrue condition start; // } // break: SyntaxNode syntax = loop.Syntax; var startLabel = new GeneratedLabelSymbol("start"); BoundStatement ifConditionGotoStart = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, true, startLabel); BoundStatement gotoContinue = new BoundGotoStatement(syntax, continueLabel); if (this.Instrument && !loop.WasCompilerGenerated) { switch (loop.Kind) { case BoundKind.WhileStatement: ifConditionGotoStart = _instrumenter.InstrumentWhileStatementConditionalGotoStartOrBreak((BoundWhileStatement)loop, ifConditionGotoStart); break; case BoundKind.ForEachStatement: ifConditionGotoStart = _instrumenter.InstrumentForEachStatementConditionalGotoStart((BoundForEachStatement)loop, ifConditionGotoStart); break; default: throw ExceptionUtilities.UnexpectedValue(loop.Kind); } // mark the initial jump as hidden. We do it to tell that this is not a part of previous statement. This // jump may be a target of another jump (for example if loops are nested) and that would give the // impression that the previous statement is being re-executed. gotoContinue = new BoundSequencePoint(null, gotoContinue); } return(BoundStatementList.Synthesized(syntax, hasErrors, gotoContinue, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, continueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, breakLabel))); }
internal static BoundStatement AddSequencePoint(VariableDeclarationSyntax declaratorSyntax, BoundStatement rewrittenStatement) { SyntaxNode node; TextSpan? part; GetBreakpointSpan(declaratorSyntax, out node, out part); var result = BoundSequencePoint.Create(declaratorSyntax, part, rewrittenStatement); result.WasCompilerGenerated = rewrittenStatement.WasCompilerGenerated; return(result); }
internal static BoundStatement AddSequencePoint(PropertyDeclarationSyntax declarationSyntax, BoundStatement rewrittenStatement) { Debug.Assert(declarationSyntax.Initializer != null); int start = declarationSyntax.Initializer.Value.SpanStart; int end = declarationSyntax.Initializer.Span.End; TextSpan part = TextSpan.FromBounds(start, end); var result = BoundSequencePoint.Create(declarationSyntax, part, rewrittenStatement); result.WasCompilerGenerated = rewrittenStatement.WasCompilerGenerated; return(result); }
private BoundStatement RewriteWhileStatement( BoundWhileStatement loop, ImmutableArray <LocalSymbol> locals, BoundExpression rewrittenCondition, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { if (locals.IsEmpty) { return(RewriteWhileStatement(loop, rewrittenCondition, rewrittenBody, breakLabel, continueLabel, hasErrors)); } // We need to enter scope-block from the top, that is where an instance of a display class will be created // if any local is captured within a lambda. // while (condition) // body; // // becomes // // continue: // { // GotoIfFalse condition break; // body // goto continue; // } // break: SyntaxNode syntax = loop.Syntax; BoundStatement continueLabelStatement = new BoundLabelStatement(syntax, continueLabel); BoundStatement ifNotConditionGotoBreak = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, breakLabel); if (this.Instrument && !loop.WasCompilerGenerated) { ifNotConditionGotoBreak = _instrumenter.InstrumentWhileStatementConditionalGotoStartOrBreak(loop, ifNotConditionGotoBreak); continueLabelStatement = new BoundSequencePoint(null, continueLabelStatement); } return(BoundStatementList.Synthesized(syntax, hasErrors, continueLabelStatement, new BoundBlock(syntax, locals, ImmutableArray.Create( ifNotConditionGotoBreak, rewrittenBody, new BoundGotoStatement(syntax, continueLabel))), new BoundLabelStatement(syntax, breakLabel))); }
private BoundStatement RewriteForStatement( BoundForStatement node, BoundStatement rewrittenInitializer, BoundExpression rewrittenCondition, BoundStatement rewrittenIncrement, BoundStatement rewrittenBody) { if (node.InnerLocals.IsEmpty) { return(RewriteForStatementWithoutInnerLocals( node, node.OuterLocals, rewrittenInitializer, rewrittenCondition, rewrittenIncrement, rewrittenBody, node.BreakLabel, node.ContinueLabel, node.HasErrors)); } // We need to enter inner_scope-block from the top, that is where an instance of a display class will be created // if any local is captured within a lambda. // for (initializer; condition; increment) // body; // // becomes the following (with block added for locals) // // { // initializer; // start: // { // GotoIfFalse condition break; // body; // continue: // increment; // goto start; // } // break: // } Debug.Assert(rewrittenBody != null); SyntaxNode syntax = node.Syntax; var statementBuilder = ArrayBuilder <BoundStatement> .GetInstance(); // initializer; if (rewrittenInitializer != null) { statementBuilder.Add(rewrittenInitializer); } var startLabel = new GeneratedLabelSymbol("start"); // start: BoundStatement startLabelStatement = new BoundLabelStatement(syntax, startLabel); if (Instrument) { startLabelStatement = new BoundSequencePoint(null, startLabelStatement); } statementBuilder.Add(startLabelStatement); var blockBuilder = ArrayBuilder <BoundStatement> .GetInstance(); // GotoIfFalse condition break; if (rewrittenCondition != null) { BoundStatement ifNotConditionGotoBreak = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, node.BreakLabel); blockBuilder.Add(ifNotConditionGotoBreak); } // body; blockBuilder.Add(rewrittenBody); // continue: // increment; blockBuilder.Add(new BoundLabelStatement(syntax, node.ContinueLabel)); if (rewrittenIncrement != null) { blockBuilder.Add(rewrittenIncrement); } // goto start; blockBuilder.Add(new BoundGotoStatement(syntax, startLabel)); statementBuilder.Add(new BoundBlock(syntax, node.InnerLocals, blockBuilder.ToImmutableAndFree())); // break: statementBuilder.Add(new BoundLabelStatement(syntax, node.BreakLabel)); var statements = statementBuilder.ToImmutableAndFree(); return(new BoundBlock(syntax, node.OuterLocals, statements, node.HasErrors)); }
private BoundStatement RewriteForStatementWithoutInnerLocals( BoundLoopStatement original, ImmutableArray <LocalSymbol> outerLocals, BoundStatement rewrittenInitializer, BoundExpression rewrittenCondition, BoundStatement rewrittenIncrement, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { Debug.Assert(original.Kind == BoundKind.ForStatement || original.Kind == BoundKind.ForEachStatement); Debug.Assert(rewrittenBody != null); // The sequence point behavior exhibited here is different from that of the native compiler. In the native // compiler, if you have something like // // for([|int i = 0, j = 0|]; ; [|i++, j++|]) // // then all the initializers are treated as a single sequence point, as are // all the loop incrementors. // // We now make each one individually a sequence point: // // for([|int i = 0|], [|j = 0|]; ; [|i++|], [|j++|]) // // If we decide that we want to preserve the native compiler stepping behavior // then we'll need to be a bit fancy here. The initializer and increment statements // can contain lambdas whose bodies need to have sequence points inserted, so we // need to make sure we visit the children. But we'll also need to make sure that // we do not generate one sequence point for each statement in the initializers // and the incrementors. SyntaxNode syntax = original.Syntax; var statementBuilder = ArrayBuilder <BoundStatement> .GetInstance(); if (rewrittenInitializer != null) { statementBuilder.Add(rewrittenInitializer); } var startLabel = new GeneratedLabelSymbol("start"); // for (initializer; condition; increment) // body; // // becomes the following (with block added for locals) // // { // initializer; // goto end; // start: // body; // continue: // increment; // end: // GotoIfTrue condition start; // break: // } var endLabel = new GeneratedLabelSymbol("end"); // initializer; // goto end; BoundStatement gotoEnd = new BoundGotoStatement(syntax, endLabel); if (this.Instrument) { // Mark the initial jump as hidden. // We do it to tell that this is not a part of previous statement. // This jump may be a target of another jump (for example if loops are nested) and that will make // impression of the previous statement being re-executed gotoEnd = new BoundSequencePoint(null, gotoEnd); } statementBuilder.Add(gotoEnd); // start: // body; statementBuilder.Add(new BoundLabelStatement(syntax, startLabel)); statementBuilder.Add(rewrittenBody); // continue: // increment; statementBuilder.Add(new BoundLabelStatement(syntax, continueLabel)); if (rewrittenIncrement != null) { statementBuilder.Add(rewrittenIncrement); } // end: // GotoIfTrue condition start; statementBuilder.Add(new BoundLabelStatement(syntax, endLabel)); BoundStatement branchBack = null; if (rewrittenCondition != null) { branchBack = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, true, startLabel); } else { branchBack = new BoundGotoStatement(syntax, startLabel); } if (this.Instrument) { switch (original.Kind) { case BoundKind.ForEachStatement: branchBack = _instrumenter.InstrumentForEachStatementConditionalGotoStart((BoundForEachStatement)original, branchBack); break; default: throw ExceptionUtilities.UnexpectedValue(original.Kind); } } statementBuilder.Add(branchBack); // break: statementBuilder.Add(new BoundLabelStatement(syntax, breakLabel)); var statements = statementBuilder.ToImmutableAndFree(); return(new BoundBlock(syntax, outerLocals, statements, hasErrors)); }