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);
                    }
                }
            }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
            }
        }
Beispiel #4
0
        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);
            }
        }
Beispiel #5
0
        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);
            }
        }
Beispiel #6
0
        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;
        }
Beispiel #7
0
        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();
            }
        }
Beispiel #8
0
            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");
                    }
                }
            }
Beispiel #9
0
        //
        // 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;
        }
Beispiel #10
0
            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");
                    }
                }
            }