public void AddBlockLabel(BasicBlock block, string label) { if (basicBlockToLabel != null && !basicBlockToLabel.ContainsKey(block)) { // Debug.Assert(!basicBlockToLabel.ContainsKey(block)); basicBlockToLabel[block] = label; } }
internal BasicBlock(Statement statement, BasicBlock unconditionalTarget) : this(statement, null, null, unconditionalTarget) { }
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; }
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; }
private void PushExceptionContext(BasicBlock handler) { handlerBlocks.Push(handler); }
private void PushContinuationStack(BasicBlock block) { continuationStack.Push(block); }
// 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)); }
private BasicBlock AddBlock(BasicBlock block) { block.Id = nextBlockId++; block.Scope = this.scopeStack.Peek(); if (insideAtomicBlock) block.RelativeAtomicLevel = 1; blockList.Add(block); return block; }
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; }
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; }
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; }
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; }
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; }
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; }
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() ) ) ); } } }
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) ) ) ) ); } }