private void PatchRunnableMethod(Class methodClass, List<BasicBlock> basicBlocks)
{
Method runnableJSMethod = (Method)
Templates.GetMemberByName(methodClass.Members, "GetRunnableJoinStatements");
Debug.Assert(runnableJSMethod.Body.Statements[0] is System.Compiler.Switch);
System.Compiler.Switch switchStmt = (System.Compiler.Switch)runnableJSMethod.Body.Statements[0];
Normalizer normalizer = new Normalizer(this, null, false);
foreach (BasicBlock block in basicBlocks)
{
SwitchCase newCase;
if (block.selectStmt != null)
{
Expression runnableExpr = null;
for (int i = 0, n = block.selectStmt.joinStatementList.Length; i < n; i++)
{
Expression jsRunnable = normalizer.GetRunnablePredicate(block.selectStmt.joinStatementList[i]);
if (jsRunnable == null)
continue;
Expression jsRunnableBit = Templates.GetExpressionTemplate("JoinStatementRunnableBit");
Replacer.Replace(jsRunnableBit, "_jsRunnableBoolExpr", jsRunnable);
Replacer.Replace(jsRunnableBit, "_jsBitMask", (Expression)new Literal((ulong)(1 << i), SystemTypes.UInt64));
if (runnableExpr == null)
runnableExpr = jsRunnableBit;
else
runnableExpr = new BinaryExpression(runnableExpr, jsRunnableBit, NodeType.Or, block.selectStmt.SourceContext);
}
if (runnableExpr != null)
{
newCase = ((System.Compiler.Switch)Templates.GetStatementTemplate("RunnableSwitchSelect")).Cases[0];
Replacer.Replace(newCase, "_BlockName", new Identifier(block.Name));
Replacer.Replace(newCase, "_expr", runnableExpr);
switchStmt.Cases.Add(newCase);
}
//
// Now check for blocks that flow atomically into this one and add cases for them
// as well. This can happen when the target of a "goto" is a label preceding a
// select statement.
//
foreach (BasicBlock previousBlock in basicBlocks)
{
if (previousBlock.UnconditionalTarget == block && previousBlock.ConditionalTarget == null &&
previousBlock.Statement == null && previousBlock.MiddleOfTransition)
{
newCase = ((System.Compiler.Switch)Templates.GetStatementTemplate("RelatedSwitchSelect")).Cases[0];
Replacer.Replace(newCase, "_BlockName", new Identifier(previousBlock.Name));
Replacer.Replace(newCase, "_TargetName", new Identifier(block.Name));
switchStmt.Cases.Add(newCase);
}
}
}
}
}