Inheritance: System.Compiler.Statement
Esempio n. 1
0
 public void AddBlockLabel(BasicBlock block, string label)
 {
     if (basicBlockToLabel != null && !basicBlockToLabel.ContainsKey(block))
     {
         // Debug.Assert(!basicBlockToLabel.ContainsKey(block));
         basicBlockToLabel[block] = label;
     }
 }
Esempio n. 2
0
 internal BasicBlock(Statement statement, BasicBlock unconditionalTarget)
     : this(statement, null, null, unconditionalTarget)
 {
 }
Esempio n. 3
0
        internal BasicBlock(Statement statement, Expression conditionalExpression, BasicBlock conditionalTarget
            , BasicBlock unconditionalTarget)
            : base((NodeType)ZingNodeType.BasicBlock)
        {
            this.Id = -1;

            this.Statement = statement;
            ConditionalExpression = conditionalExpression;
            ConditionalTarget = conditionalTarget;
            UnconditionalTarget = unconditionalTarget;
        }
Esempio n. 4
0
        private Select VisitSelect(Select select)
        {
            if (select == null) return null;
            BasicBlock[] jsBodies = new BasicBlock[select.joinStatementList.Length];

            // Traverse each join statement body, with the current continuation
            // pointing to the statement following the "select". Remember where
            // each join statement body begins so we can wire things up correctly.
            for (int i = 0, n = select.joinStatementList.Length; i < n; i++)
            {
                PushContinuationStack();
                this.Visit(select.joinStatementList[i].statement);

                // We add an extra block in front of the body because all of the transitions
                // within the internal processing of select are atomic. We need for the
                // transition to a join statement body to be appropriate for the context
                // (atomic or not). Having an extra block here is the simplest way to do
                // that. Otherwise, for our tester blocks, we'd need for one outgoing link
                // to be atomic, and the other one not. In the case of a select within an
                // atomic block, these extra blocks should be optimized away at some point.
                jsBodies[i] = new BasicBlock(null, PopContinuationStack());
                jsBodies[i].SourceContext = select.joinStatementList[i].statement.SourceContext;
                AddBlock(jsBodies[i]);
            }

            // For each join statement, create a pair of basic blocks - one to
            // see whether the join statement is runnable, and another to do
            // any "receives" contained in the join pattern list. If there are
            // no receives to be processed, the second block may be omitted.
            //
            // We walk through the list backward to make the wiring easier.
            BasicBlock nextTester = null;

            for (int i = select.joinStatementList.Length - 1; i >= 0; i--)
            {
                JoinStatement js = select.joinStatementList[i];

                if (i == select.joinStatementList.Length - 1)
                {
                    // If we fall through all of the select test blocks, then we must have
                    // reached this select statement from within an atomic block. Otherwise,
                    // we'd know that at least one branch is runnable. In this case, we raise
                    // a well-known exception and report this as an invalid state.
                    nextTester = new BasicBlock(Templates.GetStatementTemplate("InvalidBlockingSelect"));
                    nextTester.SourceContext = select.SourceContext;
                    AddBlock(nextTester);
                    nextTester.SkipNormalizer = true;
                }

                BasicBlock jsTester = new BasicBlock(js);
                AddBlock(jsTester);
                jsTester.MiddleOfTransition = true;
                jsTester.UnconditionalTarget = nextTester;
                nextTester = jsTester;
                jsTester.ConditionalExpression = Templates.GetExpressionTemplate("JoinStatementTester");
                Replacer.Replace(jsTester.ConditionalExpression, "_jsBitMask", (Expression)new Literal((ulong)1 << i, SystemTypes.UInt64));

                bool jsHasReceives = false;
                for (int j = 0, n = js.joinPatternList.Length; j < n; j++)
                {
                    if (js.joinPatternList[j] is ReceivePattern)
                    {
                        jsHasReceives = true;
                        break;
                    }
                }

                //
                // We need an executable block if there are receives to be processed
                // OR if we need to generate any external events OR if there are
                // attributes that we need to deal with on the join statement.
                //
                if (jsHasReceives || select.visible || js.attributes != null)
                {
                    BasicBlock jsReceiver = new BasicBlock(js);
                    AddBlock(jsReceiver);
                    jsReceiver.Attributes = js.Attributes;
                    jsReceiver.MiddleOfTransition = true;
                    jsReceiver.SecondOfTwo = true;
                    jsReceiver.UnconditionalTarget = jsBodies[i];
                    jsTester.ConditionalTarget = jsReceiver;
                }
                else
                    jsTester.ConditionalTarget = jsBodies[i];
            }

            BasicBlock selectBlock = new BasicBlock(Templates.GetStatementTemplate("SelectStatementProlog"));

            if (select.deterministicSelection || select.joinStatementList.Length == 1)
            {
                // For deterministic selection, we fall directly through to the first
                // "tester" block.
                selectBlock.UnconditionalTarget = nextTester;
                selectBlock.MiddleOfTransition = true;
            }
            else
            {
                // For non-deterministic selection, we conditionally branch to a "choice" block if
                // more than one join statement is runnable. Otherwise, we fall through to the first
                // tester.
                BasicBlock choiceHelper = new BasicBlock(Templates.GetStatementTemplate("NDSelectBlock"));
                choiceHelper.UnconditionalTarget = nextTester;
                AddBlock(choiceHelper);
                choiceHelper.MiddleOfTransition = true;
                choiceHelper.SkipNormalizer = true;
                choiceHelper.SourceContext = select.SourceContext;

                selectBlock.UnconditionalTarget = nextTester;
                selectBlock.ConditionalExpression = Templates.GetExpressionTemplate("NDSelectTest");
                selectBlock.ConditionalTarget = choiceHelper;
                selectBlock.MiddleOfTransition = false;
            }

            AddBlock(selectBlock);
            selectBlock.selectStmt = select;
            selectBlock.SkipNormalizer = true;
            // selectBlock.MiddleOfTransition = true;
            selectBlock.SourceContext = select.SourceContext;

            CurrentContinuation = selectBlock;

            return select;
        }
Esempio n. 5
0
 private void PushExceptionContext(BasicBlock handler)
 {
     handlerBlocks.Push(handler);
 }
Esempio n. 6
0
 private void PushContinuationStack(BasicBlock block)
 {
     continuationStack.Push(block);
 }
Esempio n. 7
0
        // Transforms block into a single BasicBlock
        private BasicBlock CoalesceBlock(Block block, BasicBlock ctng)
        {
            // We handle:
            //
            //   - Basic blocks of coalescable statements
            //   - Atomic blocks of coalescable statements
            //   - If statements with coalescable statements
            //   - ExpressionStatements w/o MethodCalls and Choose
            //   - AssignmentStatements w/o MethodCalls and Choose
            //
            if (block.NodeType != NodeType.Block)
            {
                StatementList stmts = block.Statements;
                int len = stmts.Count, i;

                for (i = 0; i < len; i++)
                    if (stmts[i] != null)
                        break;

                if (i < len)
                    block = new Block(stmts, stmts[i].SourceContext);
                else
                    block = new Block(stmts, block.SourceContext);
            }
            return AddBlock(new BasicBlock((Statement)block, ctng));
        }
Esempio n. 8
0
        private BasicBlock AddBlock(BasicBlock block)
        {
            block.Id = nextBlockId++;
            block.Scope = this.scopeStack.Peek();

            if (insideAtomicBlock)
                block.RelativeAtomicLevel = 1;
            blockList.Add(block);
            return block;
        }
Esempio n. 9
0
        public override Statement VisitWhile(While While)
        {
            if (While == null || While.Condition == null)
                return While;

            if (insideAtomicBlock && IsCoalescableWhileStmt(While))
            {
                CurrentContinuation =
                    AddBlock(new BasicBlock(While, CurrentContinuation));
                return While;
            }

            Normalizer normalizer = new Normalizer(splicer, null, false);
            BasicBlock testBlock = new BasicBlock(null);
            testBlock.SourceContext = While.Condition.SourceContext;

            PushContinuationStack(testBlock);
            this.Visit(While.Body);
            BasicBlock bodyBlock = PopContinuationStack();

            testBlock.ConditionalExpression = normalizer.VisitExpression(While.Condition);
            testBlock.ConditionalTarget = bodyBlock;
            testBlock.UnconditionalTarget = CurrentContinuation;

            testBlock.ConditionalExpression.SourceContext = testBlock.SourceContext;
            CurrentContinuation = AddBlock(testBlock);

            return While;
        }
Esempio n. 10
0
        public override Statement VisitThrow(Throw Throw)
        {
            Statement setExceptionStmt = Templates.GetStatementTemplate("SetException");
            Debug.Assert(Throw.Expression is Identifier);
            Replacer.Replace(setExceptionStmt, "_exception", Throw.Expression);

            BasicBlock raiseBlock = new BasicBlock(null);
            raiseBlock.SkipNormalizer = true;
            raiseBlock.SourceContext = Throw.SourceContext;
            raiseBlock.MiddleOfTransition = true;
            AddBlock(raiseBlock);

            if (this.CurrentHandlerBlock != null)
            {
                // If we have a handler, pass control locally
                raiseBlock.Statement = setExceptionStmt;
                raiseBlock.UnconditionalTarget = this.CurrentHandlerBlock;
            }
            else
            {
                // No local handler, so propagate outward immediately.
                Block b = new Block(new StatementList());
                b.Statements.Add(setExceptionStmt);
                b.Statements.Add(Templates.GetStatementTemplate("PropagateException"));
                raiseBlock.Statement = b;
                raiseBlock.PropagatesException = true;
            }

            CurrentContinuation = raiseBlock;

            return Throw;
        }
Esempio n. 11
0
        public override Statement VisitLabeledStatement(LabeledStatement lStatement)
        {
            if (lStatement == null) return null;

            BasicBlock savedCC = CurrentContinuation;
            this.Visit(lStatement.Statement);

            // If this is a branch target, make sure we build a separate BB for it.
            if (splicer.referencedLabels[lStatement.UniqueKey] != null)
            {
                BasicBlock bbTarget = (BasicBlock)branchTargets[lStatement.UniqueKey];

                if (bbTarget == null)
                {
                    bbTarget = new BasicBlock(null);
                    AddBlock(bbTarget);
                    bbTarget.MiddleOfTransition = true;
                    branchTargets[lStatement.UniqueKey] = bbTarget;
                }

                // fix for the "Label:; atomic { ... }" problem
                if (savedCC == CurrentContinuation &&
                    ((insideAtomicBlock && (savedCC.RelativeAtomicLevel == 0)) ||
                    (!insideAtomicBlock && (savedCC.RelativeAtomicLevel > 0))))
                {
                    // create a new basic block with the correct
                    // atomiticity level
                    CurrentContinuation = AddBlock(new BasicBlock(null, CurrentContinuation));
                }

                // Link this target block onto the front of the current chain
                bbTarget.UnconditionalTarget = CurrentContinuation;
                CurrentContinuation = bbTarget;
            }

            splicer.AddBlockLabel(CurrentContinuation, lStatement.Label.Name.Substring(3));

            return lStatement;
        }
Esempio n. 12
0
        public override Statement VisitForEach(ForEach forEach)
        {
            Normalizer normalizer = new Normalizer(false);
            Identifier incrVar = new Identifier("____" + forEach.UniqueKey.ToString(CultureInfo.InvariantCulture));

            Expression sourceEnumerable = normalizer.VisitExpression(forEach.SourceEnumerable);

            Statement incrStmt = Templates.GetStatementTemplate("foreachIncrementer");
            Replacer.Replace(incrStmt, "_iterator", incrVar);
            BasicBlock incrBlock = new BasicBlock(incrStmt);
            AddBlock(incrBlock);
            incrBlock.MiddleOfTransition = true;
            incrBlock.SkipNormalizer = true;
            incrBlock.SourceContext = forEach.SourceContext;

            PushContinuationStack(incrBlock);
            this.Visit(forEach.Body);
            BasicBlock bodyBlock = PopContinuationStack();

            Statement derefStmt = Templates.GetStatementTemplate("foreachDeref");
            Replacer.Replace(derefStmt, "_tmpVar",
                             normalizer.VisitExpression(forEach.TargetVariable));
            Replacer.Replace(derefStmt, "_collectionExpr", sourceEnumerable);
            Replacer.Replace(derefStmt, "_collectionType",
                             new Identifier(forEach.SourceEnumerable.Type.FullName));
            Replacer.Replace(derefStmt, "_iterator", incrVar);
            BasicBlock derefBlock = new BasicBlock(derefStmt, bodyBlock);
            AddBlock(derefBlock);
            derefBlock.MiddleOfTransition = true;
            derefBlock.SkipNormalizer = true;

            Expression testExpr = Templates.GetExpressionTemplate("foreachTest");
            Replacer.Replace(testExpr, "_iterator", incrVar);
            Replacer.Replace(testExpr, "_sourceEnumerable", sourceEnumerable);
            BasicBlock testBlock = new BasicBlock(null, testExpr, derefBlock, CurrentContinuation);
            AddBlock(testBlock);
            testBlock.SkipNormalizer = true;

            incrBlock.UnconditionalTarget = testBlock;

            Statement initStmt = Templates.GetStatementTemplate("foreachInit");
            Replacer.Replace(initStmt, "_iterator", incrVar);
            BasicBlock initBlock = new BasicBlock(initStmt, testBlock);
            AddBlock(initBlock);
            initBlock.MiddleOfTransition = true;
            initBlock.SkipNormalizer = true;
            initBlock.SourceContext = forEach.SourceContext;

            CurrentContinuation = initBlock;

            return forEach;
        }
Esempio n. 13
0
        public override Statement VisitBranch(Branch branch)
        {
            if (branch == null) return null;
            if (branch.Condition != null)
                throw new InvalidOperationException("Unexpected branch condition in BBSplitter");

            // Check to see if a basic block has been created for this target yet
            BasicBlock bbTarget = (BasicBlock)branchTargets[branch.Target.UniqueKey];

            // If not, create one now and register it in branchTargets
            if (bbTarget == null)
            {
                bbTarget = new BasicBlock(null);
                AddBlock(bbTarget);
                bbTarget.SourceContext = branch.SourceContext;
                bbTarget.MiddleOfTransition = true;
                branchTargets[branch.Target.UniqueKey] = bbTarget;
            }

            #if false
            // Note: this optimization was overly aggressive because it assumes that branch targets
            // fall within the current atomic block. If not, then we need an extra "branch" block
            // which can be the end of the atomic block.

            if (this.insideAtomicBlock)
            {
                // We don't need a basic block for the branch itself. We just redirect the
                // CurrentContinuation to the target of the branch.

                CurrentContinuation = bbTarget;
            }
            else
            #endif
            {
                // If we aren't in an atomic block, we can't optimize away the block for the
                // goto itself.
                BasicBlock branchBlock = new BasicBlock(null, bbTarget);
                AddBlock(branchBlock);
                branchBlock.SourceContext = branch.SourceContext;
                CurrentContinuation = branchBlock;

                // Remember this branch if it happens to be inside an atomic block. If the
                // target is *not* within the atomic block, then we'll need to do some
                // fixup work later.
                if (this.insideAtomicBlock)
                    atomicBranches.Add(branchBlock);
            }

            return branch;
        }
Esempio n. 14
0
        private ZTry VisitZTry(ZTry Try)
        {
            BasicBlock testerChain = null;

            //
            // Build a sequence of basic blocks to test the thrown exception type
            // and dispatch it to the appropriate handler. Check first to see if
            // a default handler is provided. If not, we need to create one here
            // and fall through to it if no matching handler is found.
            //
            if (Try.Catchers.Length > 0 && Try.Catchers[Try.Catchers.Length - 1].Name != null)
            {
                // No default handler, so we need to put a default of our
                // own in place to rethrow the exception. If we have an
                // outer exception context in this method, then we can
                // simply transfer control there. Otherwise, we need to
                // emit a block to make the runtime pass it up the stack.
                BasicBlock defaultHandler = null;
                if (this.CurrentHandlerBlock != null)
                {
                    // Empty block just transfers control to the outer handler
                    defaultHandler = new BasicBlock(null, this.CurrentHandlerBlock);
                }
                else
                {
                    defaultHandler = new BasicBlock(Templates.GetStatementTemplate("PropagateException"));
                    defaultHandler.PropagatesException = true;
                }
                defaultHandler.MiddleOfTransition = true;
                defaultHandler.SkipNormalizer = true;
                AddBlock(defaultHandler);
                testerChain = defaultHandler;
            }

            //
            // We traverse the list of catchers in reverse order to make
            // sure the default "with" (if any) is handled first, as it's
            // guaranteed (by the parser) to be the last one in the list.
            //
            for (int i = Try.Catchers.Length - 1; i >= 0; i--)
            {
                With with = Try.Catchers[i];

                this.PushContinuationStack();
                this.Visit(with.Block);
                BasicBlock catchBody = this.PopContinuationStack();

                if (!this.insideAtomicBlock)
                {
                    // If we aren't inside an atomic block, then we need an extra block
                    // between the tester and the body of the specific handler. All of
                    // the blocks involved in testing the exception are connected in
                    // an atomic way. If the handler isn't also going to be reached
                    // atomically, then we need an extra block with a non-atomic link
                    // to the body.
                    BasicBlock bodyConnector = new BasicBlock(null, catchBody);
                    AddBlock(bodyConnector);
                    catchBody = bodyConnector;
                }

                BasicBlock catchTester = new BasicBlock(null);

                if (with.Name != null)
                {
                    Expression catchTestExpr = Templates.GetExpressionTemplate("CatchTest");
                    Replacer.Replace(catchTestExpr, "_exception", (Expression)with.Name);
                    catchTester.ConditionalExpression = catchTestExpr;
                    catchTester.ConditionalTarget = catchBody;
                    catchTester.UnconditionalTarget = testerChain;
                }
                else
                {
                    // We're the default catch clause, so no test is necessary.
                    catchTester.UnconditionalTarget = catchBody;
                }
                catchTester.SkipNormalizer = true;
                catchTester.MiddleOfTransition = true;
                AddBlock(catchTester);

                // We just linked the new tester to the front of the tester chain.
                // This tester becomes the new head.
                testerChain = catchTester;
            }

            // All of the catch handlers are in place. Add a statement to the first handler
            // to reset the current handler block. If there's an outer scope, we point there.
            // If not, we point to "None".
            if (testerChain == null)        // could be null if all handlers had syntax errors
                return Try;

            testerChain.Statement = Templates.GetStatementTemplate("SetHandler");
            if (CurrentHandlerBlock != null)
            {
                Replacer.Replace(testerChain.Statement, "_blockName", new Identifier(CurrentHandlerBlock.Name));
                testerChain.handlerTarget = CurrentHandlerBlock;
            }
            else
                Replacer.Replace(testerChain.Statement, "_blockName", new Identifier("None"));

            // Now begin processing the body of the try block. Push the exception context
            // before starting.
            this.PushExceptionContext(testerChain);

            this.Visit(Try.Body);

            // Now create a basic block to establish the current handler as we enter the
            // body of the "try".
            Statement setHandlerStmt = Templates.GetStatementTemplate("SetHandler");
            Replacer.Replace(setHandlerStmt, "_blockName",
                             new Identifier(CurrentHandlerBlock.Name));
            BasicBlock setHandler = new BasicBlock(setHandlerStmt, CurrentContinuation);
            setHandler.MiddleOfTransition = true;
            setHandler.SkipNormalizer = true;
            setHandler.handlerTarget = CurrentHandlerBlock;
            AddBlock(setHandler);
            CurrentContinuation = setHandler;

            this.PopExceptionContext();

            return Try;
        }
Esempio n. 15
0
        private void AddScopeCleanupCalls(StatementList stmts, BasicBlock source, BasicBlock target, List<Scope> nonTrivialScopes)
        {
            // No scope change, so nothing needed here
            if (source.Scope == target.Scope)
                return;

            //
            // Scopes are different. Figure out if we're moving in or out. If the target scope
            // isn't "outward", then do nothing.
            for (Scope scope = source.Scope; scope != target.Scope; scope = scope.OuterScope)
            {
                // If we encounter the method-level scope, then this must be an inward move
                if (scope is MethodScope)
                    return;
            }

            // It's an outward move, so call the cleanup method for each scope that we're exiting
            for (Scope scope = source.Scope; scope != target.Scope; scope = scope.OuterScope)
            {
                Debug.Assert(scope != null);

                if (nonTrivialScopes.Contains(scope))
                {
                    stmts.Add(
                        new ExpressionStatement(
                            new MethodCall(
                                Identifier.For("Scope" + scope.UniqueKey.ToString()),
                                new ExpressionList()
                            )
                        )
                    );
                }
            }
        }
Esempio n. 16
0
        private void AddBlockMethod(ZMethod zMethod, Class methodClass, BasicBlock block, List<Scope> nonTrivialScopes)
        {
            Method blockMethod = (Method)Templates.GetTypeTemplateByName("BlockMethod").Members[0];
            blockMethod.Name = new Identifier(block.Name);
            methodClass.Members.Add(blockMethod);
            blockMethod.DeclaringType = methodClass;

            // Generate the appropriate closing statements for the block. Indicate if the
            // block terminates an atomic region and establish the transfer of control to
            // the next block(s) or out of the method.

            if ((ZingCompilerOptions.IsPreemtive && !block.MiddleOfTransition && !block.IsReturn) || (block.Yields))
            {
                // p.MiddleOfTransition = false;
                blockMethod.Body.Statements.Add(
                    new ExpressionStatement(
                        new AssignmentExpression(
                            new AssignmentStatement(
                                new QualifiedIdentifier(Identifier.For("p"), Identifier.For("MiddleOfTransition")),
                                new Literal(false, SystemTypes.Boolean)
                            )
                        )
                    )
                );
            }

            // p.AtomicityLevel = this.SavedAtomicityLevel + X;
            blockMethod.Body.Statements.Add(
                new ExpressionStatement(
                    new AssignmentExpression(
                        new AssignmentStatement(
                            new QualifiedIdentifier(Identifier.For("p"), Identifier.For("AtomicityLevel")),
                            new BinaryExpression(
                                new QualifiedIdentifier(new This(), Identifier.For("SavedAtomicityLevel")),
                                new Literal(block.RelativeAtomicLevel, SystemTypes.Int32),
                                NodeType.Add
                            )
                        )
                    )
                )
            );

            #if false
            //
            // The following code was added for summarization, but isn't quite right. It
            // updates the nextBlock too early for some blocks. -- Tony
            //
            //
            // when generating summaries of type MaxCall, we need to
            // know the value of nextBlock before we invoke p.Call().
            // the first of the two basic blocks of a Zing method call
            // is guaranteed to fall through, so we only need to lift
            // the assignment of nextBlock for fall-through blocks.
            if (block.ConditionalTarget == null && block.UnconditionalTarget != null)
            {
                stmt = Templates.GetStatementTemplate("UnconditionalBlockTransfer");
                Replacer.Replace(stmt, "_UnconditionalBlock",
                                 new Identifier(block.UnconditionalTarget.Name));
                blockMethod.Body.Statements.Add(stmt);
            }
            #endif

            if (block.Attributes != null)
            {
                Duplicator duplicator = new Duplicator(null, null);

                for (int i = 0, n = block.Attributes.Count; i < n; i++)
                {
                    if (block.Attributes[i] == null)
                        continue;

                    AttributeNode dupAttr = duplicator.VisitAttributeNode(block.Attributes[i]);

                    Normalizer normalizer = new Normalizer(false);
                    ExpressionList attrParams = normalizer.VisitExpressionList(dupAttr.Expressions);

                    // application.Trace(_context, _contextAttr, new Z.Attributes._attrName(...) );
                    ExpressionStatement traceStmt = new ExpressionStatement(
                        new MethodCall(
                            new QualifiedIdentifier(Identifier.For("application"), Identifier.For("Trace")),
                            new ExpressionList(
                                SourceContextConstructor(dupAttr.SourceContext),
                                new Literal(null, SystemTypes.Object),
                                new Construct(
                                    new MemberBinding(
                                        null,
                                        new TypeExpression(
                                            new QualifiedIdentifier(
                                                new QualifiedIdentifier(Identifier.For("Z"), Identifier.For("Attributes")),
                                                dupAttr.Type.Name
                                            )
                                        )
                                    ),
                                    attrParams
                                )
                            )
                        )
                    );
                    blockMethod.Body.Statements.Add(traceStmt);
                }
            }

            if (block.Statement != null)
            {
                if (block.SkipNormalizer)
                    blockMethod.Body.Statements.Add(block.Statement);
                else
                {
                    // Do statement-level code-gen pass on the block's statement
                    Normalizer normalizer = new Normalizer(this, block.Attributes, block.SecondOfTwo);

                    blockMethod.Body.Statements.Add((Statement)normalizer.Visit(block.Statement));
                }
            }

            if (block.ConditionalTarget != null && block.ConditionalExpression != null)
            {
                Block trueBlock, falseBlock;

                // if (_conditionalExpression)
                //     nextBlock = Blocks._conditionalTarget;
                // else
                //     nextBlock = Blocks._unconditionalTarget;
                blockMethod.Body.Statements.Add(
                    new If(
                        block.ConditionalExpression,
                        trueBlock = new Block(new StatementList(
                            new ExpressionStatement(
                                new AssignmentExpression(
                                    new AssignmentStatement(
                                        Identifier.For("nextBlock"),
                                        new QualifiedIdentifier(
                                            Identifier.For("Blocks"),
                                            Identifier.For(block.ConditionalTarget.Name)
                                        )
                                    )
                                )
                            )
                        )),
                        falseBlock = new Block(new StatementList(
                            new ExpressionStatement(
                                new AssignmentExpression(
                                    new AssignmentStatement(
                                        Identifier.For("nextBlock"),
                                        new QualifiedIdentifier(
                                            Identifier.For("Blocks"),
                                            Identifier.For(block.UnconditionalTarget.Name)
                                        )
                                    )
                                )
                            )
                        ))
                    )
                );

                AddScopeCleanupCalls(trueBlock.Statements, block, block.ConditionalTarget, nonTrivialScopes);
                AddScopeCleanupCalls(falseBlock.Statements, block, block.UnconditionalTarget, nonTrivialScopes);
            }
            else if (block.UnconditionalTarget != null)
            {
                // nextBlock = Blocks.X;
                blockMethod.Body.Statements.Add(
                    new ExpressionStatement(
                        new AssignmentExpression(
                            new AssignmentStatement(
                                Identifier.For("nextBlock"),
                                new QualifiedIdentifier(Identifier.For("Blocks"), Identifier.For(block.UnconditionalTarget.Name))
                            )
                        )
                    )
                );
                AddScopeCleanupCalls(blockMethod.Body.Statements, block, block.UnconditionalTarget, nonTrivialScopes);
            }
            else if (block.IsReturn)
            {
                Debug.Assert(block.UnconditionalTarget == null);

                Statement returnCall = Templates.GetStatementTemplate("ReturnBlockTransfer");
                SourceContext context;
                Return ret = block.Statement as Return;
                if (ret != null)
                {
                    context = ret.SourceContext;
                }
                else
                {
                    // If not a return stmt, the context is the closing brace of the method
                    context = zMethod.SourceContext;
                    context.StartPos = context.EndPos - 1;
                }

                Replacer.Replace(returnCall, "_context", SourceContextConstructor(context));
                Replacer.Replace(returnCall, "_contextAttr", ContextAttributeConstructor(block.Attributes));

                blockMethod.Body.Statements.Add(returnCall);

                // StateImpl.IsReturn = true;
                blockMethod.Body.Statements.Add(
                    new ExpressionStatement(
                        new AssignmentExpression(
                            new AssignmentStatement(
                                new QualifiedIdentifier(Identifier.For("StateImpl"), Identifier.For("IsReturn")),
                                new Literal(true, SystemTypes.Boolean)
                            )
                        )
                    )
                );
            }
        }