public override BoundNode VisitConditionalGoto(BoundConditionalGoto node) { BoundSpillSequenceBuilder builder = null; var condition = VisitExpression(ref builder, node.Condition); return(UpdateStatement(builder, node.Update(condition, node.JumpIfTrue, node.Label))); }
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))); }
public override BoundNode VisitDoStatement(BoundDoStatement node) { Debug.Assert(node != null); var rewrittenCondition = (BoundExpression)Visit(node.Condition); var rewrittenBody = (BoundStatement)Visit(node.Body); var startLabel = new GeneratedLabelSymbol("start"); var syntax = node.Syntax; // EnC: We need to insert a hidden sequence point to handle function remapping in case // the containing method is edited while methods invoked in the condition are being executed. if (!node.WasCompilerGenerated && this.Instrument) { rewrittenCondition = _instrumenter.InstrumentDoStatementCondition(node, rewrittenCondition, _factory); } BoundStatement ifConditionGotoStart = new BoundConditionalGoto(syntax, rewrittenCondition, true, startLabel); if (!node.WasCompilerGenerated && this.Instrument) { ifConditionGotoStart = _instrumenter.InstrumentDoStatementConditionalGotoStart(node, ifConditionGotoStart); } // do // body // while (condition); // // becomes // // start: // { // body // continue: // sequence point // GotoIfTrue condition start; // } // break: if (node.Locals.IsEmpty) { return(BoundStatementList.Synthesized(syntax, node.HasErrors, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, node.ContinueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, node.BreakLabel))); } return(BoundStatementList.Synthesized(syntax, node.HasErrors, new BoundLabelStatement(syntax, startLabel), new BoundBlock(syntax, node.Locals, ImmutableArray.Create <BoundStatement>(rewrittenBody, new BoundLabelStatement(syntax, node.ContinueLabel), ifConditionGotoStart)), new BoundLabelStatement(syntax, node.BreakLabel))); }
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))); }
internal void Parse(BoundConditionalGoto boundConditionalGoto) { if (boundConditionalGoto == null) { throw new ArgumentNullException(); } this.Condition = Deserialize(boundConditionalGoto.Condition) as Expression; this.JumpIfTrue = boundConditionalGoto.JumpIfTrue; var localLabel = new Label(); localLabel.Parse(boundConditionalGoto.Label); this.Label = localLabel; }
private BoundStatement RewriteWhileStatement( SyntaxNode syntax, BoundExpression rewrittenCondition, TextSpan conditionSequencePointSpan, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { var startLabel = new GeneratedLabelSymbol("start"); BoundStatement ifConditionGotoStart = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, true, startLabel); if (this.generateDebugInfo) { ifConditionGotoStart = new BoundSequencePointWithSpan(syntax, ifConditionGotoStart, conditionSequencePointSpan); } // while (condition) // body; // // becomes // // goto continue; // start: // body // continue: // GotoIfTrue condition start; // break: BoundStatement gotoContinue = new BoundGotoStatement(syntax, continueLabel); if (this.generateDebugInfo) { //mark the initial jump as hidden. //We do it to tell that this is not a part of previou 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 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))); }
public override BoundNode VisitDoStatement(BoundDoStatement node) { Debug.Assert(node != null); var rewrittenCondition = (BoundExpression)Visit(node.Condition); var rewrittenBody = (BoundStatement)Visit(node.Body); var startLabel = new GeneratedLabelSymbol("start"); var syntax = node.Syntax; BoundStatement ifConditionGotoStart = new BoundConditionalGoto(syntax, rewrittenCondition, true, startLabel); if (this.generateDebugInfo) { var doSyntax = (DoStatementSyntax)syntax; var span = TextSpan.FromBounds( doSyntax.WhileKeyword.Span.Start, doSyntax.SemicolonToken.Span.End); ifConditionGotoStart = new BoundSequencePointWithSpan(doSyntax, ifConditionGotoStart, span); } // do // body // while (condition); // // becomes // // start: // body // continue: // sequence point // GotoIfTrue condition start; // break: return(BoundStatementList.Synthesized(syntax, node.HasErrors, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, node.ContinueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, node.BreakLabel))); }
private void EmitConditionalGoto(BoundConditionalGoto boundConditionalGoto) { object label = boundConditionalGoto.Label; Debug.Assert(label != null); EmitCondBranch(boundConditionalGoto.Condition, ref label, boundConditionalGoto.JumpIfTrue); }
public override BoundNode VisitConditionalGoto(BoundConditionalGoto node) { var labelClone = GetLabelClone(node.Label); // expressions do not contain labels or branches BoundExpression condition = node.Condition; return node.Update(condition, node.JumpIfTrue, labelClone); }
private void EmitConditionalGoto(BoundConditionalGoto boundConditionalGoto) { if (noOptimizations) { //TODO: what is the point of this? //native compiler does intentional dead-store here. Does it still help debugging? var boolTemp = AllocateTemp(boundConditionalGoto.Condition.Type, boundConditionalGoto.Condition.Syntax); ConstResKind crk = EmitCondExpr(boundConditionalGoto.Condition, boundConditionalGoto.JumpIfTrue); builder.EmitLocalStore(boolTemp); switch (crk) { case ConstResKind.ConstFalse: break; case ConstResKind.ConstTrue: builder.EmitBranch(ILOpCode.Br, boundConditionalGoto.Label); break; case ConstResKind.NotAConst: builder.EmitLocalLoad(boolTemp); builder.EmitBranch(ILOpCode.Brtrue, boundConditionalGoto.Label); break; default: Debug.Assert(false); goto case ConstResKind.NotAConst; } this.FreeTemp(boolTemp); } else { object label = boundConditionalGoto.Label; Debug.Assert(label != null); EmitCondBranch(boundConditionalGoto.Condition, ref label, boundConditionalGoto.JumpIfTrue); } }
public override BoundNode VisitConditionalGoto(BoundConditionalGoto node) { Debug.Assert(node.Label == _currentFinallyFrame.ProxyLabelIfNeeded(node.Label), "conditional leave?"); return(base.VisitConditionalGoto(node)); }
/// <summary> /// Generate a thread-safe accessor for a regular field-like event. /// /// DelegateType tmp0 = _event; //backing field /// DelegateType tmp1; /// DelegateType tmp2; /// do { /// tmp1 = tmp0; /// tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -= /// tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1); /// } while ((object)tmp0 != (object)tmp1); /// /// Note, if System.Threading.Interlocked.CompareExchange<T> is not available, /// we emit the following code and mark the method Synchronized (unless it is a struct). /// /// _event = (DelegateType)Delegate.Combine(_event, value); //Remove for -= /// /// </summary> internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics) { CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode; TypeSymbol delegateType = eventSymbol.Type.TypeSymbol; MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod; ParameterSymbol thisParameter = accessor.ThisParameter; TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean); SpecialMember updateMethodId = isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove; MethodSymbol updateMethod = (MethodSymbol)compilation.GetSpecialTypeMember(updateMethodId); BoundStatement @return = new BoundReturnStatement(syntax, refKind: RefKind.None, expressionOpt: null) { WasCompilerGenerated = true }; if (updateMethod == null) { MemberDescriptor memberDescriptor = SpecialMembers.GetDescriptor(updateMethodId); diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.ERR_MissingPredefinedMember, memberDescriptor.DeclaringTypeMetadataName, memberDescriptor.Name), syntax.Location)); return(BoundBlock.SynthesizedNoLocals(syntax, @return)); } Binder.ReportUseSiteDiagnostics(updateMethod, diagnostics, syntax); BoundThisReference fieldReceiver = eventSymbol.IsStatic ? null : new BoundThisReference(syntax, thisParameter.Type.TypeSymbol) { WasCompilerGenerated = true }; BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax, receiver: fieldReceiver, fieldSymbol: eventSymbol.AssociatedField, constantValueOpt: null) { WasCompilerGenerated = true }; BoundParameter boundParameter = new BoundParameter(syntax, parameterSymbol: accessor.Parameters[0]) { WasCompilerGenerated = true }; BoundExpression delegateUpdate; MethodSymbol compareExchangeMethod = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T); if ((object)compareExchangeMethod == null) { // (DelegateType)Delegate.Combine(_event, value) delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax, operand: BoundCall.Synthesized(syntax, receiverOpt: null, method: updateMethod, arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundParameter)), conversion: Conversion.ExplicitReference, type: delegateType); // _event = (DelegateType)Delegate.Combine(_event, value); BoundStatement eventUpdate = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundBackingField, right: delegateUpdate, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; return(BoundBlock.SynthesizedNoLocals(syntax, statements: ImmutableArray.Create <BoundStatement>( eventUpdate, @return))); } compareExchangeMethod = compareExchangeMethod.Construct(ImmutableArray.Create <TypeSymbol>(delegateType)); Binder.ReportUseSiteDiagnostics(compareExchangeMethod, diagnostics, syntax); GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop"); const int numTemps = 3; LocalSymbol[] tmps = new LocalSymbol[numTemps]; BoundLocal[] boundTmps = new BoundLocal[numTemps]; for (int i = 0; i < numTemps; i++) { tmps[i] = new SynthesizedLocal(accessor, TypeSymbolWithAnnotations.Create(delegateType), SynthesizedLocalKind.LoweringTemp); boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType); } // tmp0 = _event; BoundStatement tmp0Init = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: boundBackingField, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // LOOP: BoundStatement loopStart = new BoundLabelStatement(syntax, label: loopLabel) { WasCompilerGenerated = true }; // tmp1 = tmp0; BoundStatement tmp1Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[1], right: boundTmps[0], type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // (DelegateType)Delegate.Combine(tmp1, value) delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax, operand: BoundCall.Synthesized(syntax, receiverOpt: null, method: updateMethod, arguments: ImmutableArray.Create <BoundExpression>(boundTmps[1], boundParameter)), conversion: Conversion.ExplicitReference, type: delegateType); // tmp2 = (DelegateType)Delegate.Combine(tmp1, value); BoundStatement tmp2Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[2], right: delegateUpdate, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1) BoundExpression compareExchange = BoundCall.Synthesized(syntax, receiverOpt: null, method: compareExchangeMethod, arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1])); // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1); BoundStatement tmp0Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: compareExchange, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise BoundExpression loopExitCondition = new BoundBinaryOperator(syntax, operatorKind: BinaryOperatorKind.ObjectEqual, left: boundTmps[0], right: boundTmps[1], constantValueOpt: null, methodOpt: null, resultKind: LookupResultKind.Viable, type: boolType) { WasCompilerGenerated = true }; // branchfalse (tmp0 == tmp1) LOOP BoundStatement loopEnd = new BoundConditionalGoto(syntax, condition: loopExitCondition, jumpIfTrue: false, label: loopLabel) { WasCompilerGenerated = true }; return(new BoundBlock(syntax, locals: tmps.AsImmutable(), statements: ImmutableArray.Create <BoundStatement>( tmp0Init, loopStart, tmp1Update, tmp2Update, tmp0Update, loopEnd, @return)) { WasCompilerGenerated = true }); }
public override BoundNode VisitConditionalGoto(BoundConditionalGoto node) { CheckCanMergeWithParent(node.Label); return(base.VisitConditionalGoto(node)); }
public override BoundNode VisitDoStatement(BoundDoStatement node) { Debug.Assert(node != null); var rewrittenCondition = (BoundExpression)Visit(node.Condition); var rewrittenBody = (BoundStatement)Visit(node.Body); var startLabel = new GeneratedLabelSymbol("start"); var syntax = node.Syntax; BoundStatement ifConditionGotoStart = new BoundConditionalGoto(syntax, rewrittenCondition, true, startLabel); if (this.generateDebugInfo) { var doSyntax = (DoStatementSyntax)syntax; var span = TextSpan.FromBounds( doSyntax.WhileKeyword.Span.Start, doSyntax.SemicolonToken.Span.End); ifConditionGotoStart = new BoundSequencePointWithSpan(doSyntax, ifConditionGotoStart, span); } // do // body // while (condition); // // becomes // // start: // body // continue: // sequence point // GotoIfTrue condition start; // break: return BoundStatementList.Synthesized(syntax, node.HasErrors, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, node.ContinueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, node.BreakLabel)); }
private BoundStatement RewriteForStatement( SyntaxNode syntax, ReadOnlyArray<LocalSymbol> locals, BoundStatement rewrittenInitializer, BoundExpression rewrittenCondition, SyntaxNodeOrToken conditionSyntax, BoundStatement rewrittenIncrement, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { var startLabel = new GeneratedLabelSymbol("start"); var endLabel = new GeneratedLabelSymbol("end"); // 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: // } // initializer; // goto end; var statementBuilder = ArrayBuilder<BoundStatement>.GetInstance(); if (rewrittenInitializer != null) { statementBuilder.Add(rewrittenInitializer); } //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 var gotoEnd = new BoundSequencePoint(null, new BoundGotoStatement(syntax, endLabel)); statementBuilder.Add(gotoEnd); // start: // body; statementBuilder.Add(new BoundLabelStatement(syntax, startLabel)); Debug.Assert(rewrittenBody != null); 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.generateDebugInfo) { if (conditionSyntax.IsToken) { branchBack = new BoundSequencePointWithSpan(syntax, branchBack, conditionSyntax.Span); } else { //if there is no condition, make this a hidden point so that //it does not count as a part of previous statement branchBack = new BoundSequencePoint(conditionSyntax.AsNode(), branchBack); } } statementBuilder.Add(branchBack); // break: statementBuilder.Add(new BoundLabelStatement(syntax, breakLabel)); var statements = statementBuilder.ToReadOnlyAndFree(); return new BoundBlock(syntax, locals, statements, hasErrors); }
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)); }
private BoundStatement RewriteForStatement( SyntaxNode syntax, ReadOnlyArray <LocalSymbol> locals, BoundStatement rewrittenInitializer, BoundExpression rewrittenCondition, SyntaxNodeOrToken conditionSyntax, BoundStatement rewrittenIncrement, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { var startLabel = new GeneratedLabelSymbol("start"); var endLabel = new GeneratedLabelSymbol("end"); // 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: // } // initializer; // goto end; var statementBuilder = ArrayBuilder <BoundStatement> .GetInstance(); if (rewrittenInitializer != null) { statementBuilder.Add(rewrittenInitializer); } //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 var gotoEnd = new BoundSequencePoint(null, new BoundGotoStatement(syntax, endLabel)); statementBuilder.Add(gotoEnd); // start: // body; statementBuilder.Add(new BoundLabelStatement(syntax, startLabel)); Debug.Assert(rewrittenBody != null); 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.generateDebugInfo) { if (conditionSyntax.IsToken) { branchBack = new BoundSequencePointWithSpan(syntax, branchBack, conditionSyntax.Span); } else { //if there is no condition, make this a hidden point so that //it does not count as a part of previous statement branchBack = new BoundSequencePoint(conditionSyntax.AsNode(), branchBack); } } statementBuilder.Add(branchBack); // break: statementBuilder.Add(new BoundLabelStatement(syntax, breakLabel)); var statements = statementBuilder.ToReadOnlyAndFree(); return(new BoundBlock(syntax, locals, statements, hasErrors)); }
public override BoundNode VisitConditionalGoto(BoundConditionalGoto node) { var result = base.VisitConditionalGoto(node); PopEvalStack(); // condition gets consumed. RecordBranch(node.Label); return result; }
private BoundStatement RewriteWhileStatement( SyntaxNode syntax, BoundExpression rewrittenCondition, TextSpan conditionSequencePointSpan, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { var startLabel = new GeneratedLabelSymbol("start"); BoundStatement ifConditionGotoStart = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, true, startLabel); if (this.generateDebugInfo) { ifConditionGotoStart = new BoundSequencePointWithSpan(syntax, ifConditionGotoStart, conditionSequencePointSpan); } // while (condition) // body; // // becomes // // goto continue; // start: // body // continue: // GotoIfTrue condition start; // break: BoundStatement gotoContinue = new BoundGotoStatement(syntax, continueLabel); if (this.generateDebugInfo) { //mark the initial jump as hidden. //We do it to tell that this is not a part of previou 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 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)); }
public override BoundNode VisitConditionalGoto(BoundConditionalGoto node) { AddGoto(node.Label); return(base.VisitConditionalGoto(node)); }