public void EnsureLabelGroupExists (Dictionary<JSStatement, JSLabelGroupStatement> labelGroups) { if (LabelGroup != null) return; if (!labelGroups.TryGetValue(EnclosingBlock.Block, out LabelGroup)) { int index = labelGroups.Count; var entryBlock = new JSBlockStatement { Label = String.Format("$entry{0}", index) }; var exitBlock = new JSBlockStatement { Label = String.Format("$exit{0}", index) }; labelGroups[EnclosingBlock.Block] = LabelGroup = new JSLabelGroupStatement( index, entryBlock, exitBlock ); var bs = EnclosingBlock.Block as JSBlockStatement; if (bs != null) { bool populatingEntryBlock = true, populatingExitBlock = false; // We want to walk through the block's statements and collect them. // Statements before the labelled statement go into the entry block. // Statements after the labelled statement go into the exit block. // FIXME: Is the following rule correct? Without it, FaultBlock breaks. // If we hit another labelled statement while filling the exit block, stop filling it. for (var i = 0; i < bs.Statements.Count; i++) { var s = bs.Statements[i]; if (s.Label == Label) { populatingEntryBlock = false; populatingExitBlock = true; } else if (populatingEntryBlock) { entryBlock.Statements.Add(s); } else if (populatingExitBlock) { #pragma warning disable 0642 if (s.Label == null) exitBlock.Statements.Add(s); // HACK: The synthesized switch exit labels generated when hoisting a block out of // a switch statement shouldn't terminate statement collection. Without this hack, // ForeachInEnumeratorFunctionMonoBinary fails. else if (s.Label.StartsWith("$switchExit")) ; else populatingExitBlock = false; #pragma warning restore 0642 } } // FIXME: Is this valid? It might confuse the AstVisitor if bs is on the stack. bs.Statements.Clear(); bs.Statements.Add(LabelGroup); } else { throw new NotImplementedException("Unsupported enclosing block type: " + EnclosingBlock.Block.GetType().Name); } } }
public void VisitNode (JSLabelGroupStatement lgs) { // HACK: Issue #827 depends on loops containing labelgroups having an index // so that continues and breaks can be targeted. foreach (var ls in Stack.OfType<JSLoopStatement>()) UsedLoops.Add(ls.Index.Value); VisitChildren(lgs); }
public void VisitNode(JSLabelGroupStatement lgs) { foreach (var kvp in lgs.Labels.ToArray()) { if (UsedLabels.Contains(kvp.Key)) continue; var labelledBlock = kvp.Value as JSBlockStatement; if (labelledBlock == null) continue; if (labelledBlock.Statements.Count < 1) lgs.Labels.Remove(kvp.Key); } }
public void VisitNode (JSLabelGroupStatement lgs) { var nonNull = (from kvp in lgs.Labels where !kvp.Value.IsNull select kvp.Value).ToArray(); if (nonNull.Length == 0) { var theNull = new JSNullStatement(); ParentNode.ReplaceChild(lgs, theNull); VisitReplacement(theNull); } else if ( (nonNull.Length == 1) && !nonNull[0].AllChildrenRecursive.OfType<JSGotoExpression>().Any( (g) => g.TargetLabel == nonNull[0].Label ) ) { var onlyLabel = nonNull[0]; var labelGroupExit = onlyLabel.AllChildrenRecursive.OfType<JSExitLabelGroupExpression>().FirstOrDefault(); if (labelGroupExit != null) { /* FIXME: This doesn't work var enclosingFunction = Stack.OfType<JSFunctionExpression>().First(); var loops = enclosingFunction.AllChildrenRecursive.OfType<JSLoopStatement>(); int nextLoopIndex = 0; if (loops.Any((l) => true)) nextLoopIndex = loops.Max((l) => l.Index.GetValueOrDefault(0)) + 1; var replacement = new JSDoLoop( JSLiteral.New(false), onlyLabel ); replacement.Index = nextLoopIndex; var newBreak = new JSBreakExpression(); newBreak.TargetLoop = nextLoopIndex; onlyLabel.ReplaceChildRecursive(labelGroupExit, newBreak); ParentNode.ReplaceChild(lgs, replacement); VisitReplacement(replacement); */ VisitChildren(lgs); } else { ParentNode.ReplaceChild(lgs, onlyLabel); VisitReplacement(onlyLabel); } } else { VisitChildren(lgs); } }
public void VisitNode(JSLabelGroupStatement lgs) { var nonNull = (from kvp in lgs.Labels where !kvp.Value.IsNull select kvp.Value).ToArray(); if (nonNull.Length == 0) { var theNull = new JSNullStatement(); ParentNode.ReplaceChild(lgs, theNull); VisitReplacement(theNull); } else if ( (nonNull.Length == 1) && !nonNull[0].AllChildrenRecursive.OfType<JSGotoExpression>().Any( (g) => g.TargetLabel == nonNull[0].Label ) ) { ParentNode.ReplaceChild(lgs, nonNull[0]); VisitReplacement(nonNull[0]); } else { VisitChildren(lgs); } }
protected bool MaybeFlatten(JSLabelGroupStatement lgs, LinkedListNode<string> keyNode) { var labelledStatement = lgs.Labels[keyNode.Value]; var checkStatement = labelledStatement; JSLabelGroupStatement labelledGroup = null; // If a label contains a single-statement block, recurse down to find a label group. while (checkStatement != null) { labelledGroup = checkStatement as JSLabelGroupStatement; if (labelledGroup != null) break; var checkBlock = checkStatement as JSBlockStatement; if (checkBlock == null) break; if (checkBlock.Statements.Count != 1) break; checkStatement = checkBlock.Statements[0]; } if ( (labelledGroup != null) && (labelledGroup.Labels.Count == 3) ) { var labels = labelledGroup.Labels.ToArray(); // Hoist the contents of the entry label into the label that contains this label group. var entryLabel = labels[0]; labelledStatement.ReplaceChildRecursive(labelledGroup, entryLabel.Value); // Hoist the single label from this label group into the containing label group, // after the label that contains this label group. var hoistedLabel = labels[1]; var hoistedKeyNode = lgs.Labels.EnqueueAfter( keyNode, hoistedLabel.Key, hoistedLabel.Value ); var exitLabel = labels[2]; // Hoist the contents of the exit label into the label that contains this label group. lgs.Labels.EnqueueAfter( hoistedKeyNode, hoistedLabel.Key + "_after", exitLabel.Value ); return FlattenedAGroup = true; } return false; }
public void VisitNode(JSLabelGroupStatement lgs) { GroupStack.Push(lgs); bool restart = false; do { restart = false; foreach (var keyNode in lgs.Labels.Keys) { if (MaybeFlatten(lgs, keyNode)) { restart = true; break; } } } while (restart); try { VisitChildren(lgs); } finally { GroupStack.Pop(); } }
public void EnsureLabelGroupExists(Dictionary<JSStatement, JSLabelGroupStatement> labelGroups) { if (LabelGroup != null) return; if (!labelGroups.TryGetValue(EnclosingBlock.Block, out LabelGroup)) { int index = labelGroups.Count; var entryBlock = new JSBlockStatement { Label = String.Format("$entry{0}", index) }; var exitBlock = new JSBlockStatement { Label = String.Format("$exit{0}", index) }; labelGroups[EnclosingBlock.Block] = LabelGroup = new JSLabelGroupStatement( index, entryBlock, exitBlock ); var bs = EnclosingBlock.Block as JSBlockStatement; if (bs != null) { bool populatingEntryBlock = true, populatingExitBlock = false; // We want to walk through the block's statements and collect them. // Statements before the labelled statement go into the entry block. // Statements after the labelled statement go into the exit block. // FIXME: Is the following rule correct? Without it, FaultBlock breaks. // If we hit another labelled statement while filling the exit block, stop filling it. for (var i = 0; i < bs.Statements.Count; i++) { var s = bs.Statements[i]; if (s.Label == Label) { populatingEntryBlock = false; populatingExitBlock = true; } else if (populatingEntryBlock) { entryBlock.Statements.Add(s); } else if (populatingExitBlock) { if (s.Label == null) exitBlock.Statements.Add(s); else populatingExitBlock = false; } } bs.Statements.Clear(); bs.Statements.Add(LabelGroup); } else { throw new NotImplementedException("Unsupported enclosing block type"); } } }
// // IL Node Types // protected JSBlockStatement TranslateBlock(IEnumerable<ILNode> children) { JSBlockStatement result, currentBlock; // TODO: Fix this heuristic by building a flow graph at the beginning of method translation if (children.Any( n => ContainsLabels(n) )) { var index = LabelledBlockCount++; result = new JSLabelGroupStatement(index); currentBlock = new JSBlockStatement(); currentBlock.Label = String.Format("__entry{0}__", index); result.Statements.Add(currentBlock); } else { currentBlock = result = new JSBlockStatement(); } foreach (var node in children) { var label = node as ILLabel; var expr = node as ILExpression; var isGoto = (expr != null) && (expr.Code == ILCode.Br); if (label != null) { currentBlock = new JSBlockStatement { Label = label.Name }; result.Statements.Add(currentBlock); continue; } else if (isGoto) { currentBlock.Statements.Add(new JSExpressionStatement(new JSGotoExpression( ((ILLabel)expr.Operand).Name ))); } else { var translated = TranslateStatement(node); if (translated != null) currentBlock.Statements.Add(translated); } } return result; }
public void EnsureLabelGroupExists(Dictionary<JSStatement, JSLabelGroupStatement> labelGroups) { if (LabelGroup != null) return; if (!labelGroups.TryGetValue(EnclosingBlock.Block, out LabelGroup)) { int index = labelGroups.Count; var entryBlock = new JSBlockStatement { Label = String.Format("$entry{0}", index) }; labelGroups[EnclosingBlock.Block] = LabelGroup = new JSLabelGroupStatement(index, entryBlock); var bs = EnclosingBlock.Block as JSBlockStatement; if (bs != null) { entryBlock.Statements.AddRange(bs.Statements); bs.Statements.Clear(); bs.Statements.Add(LabelGroup); } else { throw new NotImplementedException("Unsupported enclosing block type"); } } }