Exemplo n.º 1
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);
            }
        }
Exemplo n.º 2
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");
                    }
                }
            }
Exemplo n.º 3
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();
            }
        }
Exemplo n.º 4
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);
        }
Exemplo n.º 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
                    )
                )
            {
                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);
            }
        }
Exemplo n.º 6
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);
        }
Exemplo n.º 7
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);
                }
            }
        }
Exemplo n.º 8
0
        public void VisitNode(JSLabelGroupStatement lgs)
        {
            CheckForFallthrough(lgs);

            var data = new LabelGroupData();

            LabelGroupStack.Push(data);

            foreach (var key in lgs.Labels.Keys)
            {
                data.Add(key.Value, new LabelGroupLabelData());
            }

            VisitChildren(lgs);

            // Scan all the labels to determine their direct exit label, if any
            foreach (var kvp in data)
            {
                var targetLabels = kvp.Value.ExitTargetLabels.Distinct().ToArray();

                if (
                    (targetLabels.Length == 1) &&
                    (kvp.Value.UntargettedExitCount == 0)
                    )
                {
                    kvp.Value.DirectExitLabel = targetLabels[0];
                }
                else
                {
                    kvp.Value.DirectExitLabel = null;
                }
            }

            // Scan all the labels again to determine their recursive exit label
            foreach (var kvp in data)
            {
                var rel = kvp.Value.RecursiveExitLabel = ComputeRecursiveExitLabel(data, kvp.Key);

                if (rel != null)
                {
                    data[rel].TimesUsedAsRecursiveExitTarget += 1;
                }
            }

            // If we have one label that is the recursive exit target for all other labels, we can turn it into the exit label
            var recursiveExitTargets = data.Where(
                (kvp) => kvp.Value.TimesUsedAsRecursiveExitTarget > 0
                ).ToArray();

            if (recursiveExitTargets.Length == 1)
            {
                var onlyRecursiveExitTarget = recursiveExitTargets[0].Key;
                var exitLabel        = lgs.ExitLabel;
                var newExitLabel     = lgs.Labels[onlyRecursiveExitTarget];
                var newExitLabelData = data[newExitLabel.Label];

                if (
                    (newExitLabelData.ExitTargetLabels.Count == 0) &&
                    (newExitLabelData.UntargettedExitCount == 0) &&
                    (newExitLabel != lgs.Labels.LastOrDefault().Value)
                    )
                {
                    if (TraceLevel >= 1)
                    {
                        Console.WriteLine("// Cannot mark label '{0}' as exit label because it falls through and is not the last label", onlyRecursiveExitTarget);
                    }
                }
                else if (exitLabel != null)
                {
                    if (exitLabel != newExitLabel)
                    {
                        if (TraceLevel >= 1)
                        {
                            Console.WriteLine("// Cannot mark label '{0}' as exit label because this labelgroup already has one", onlyRecursiveExitTarget);
                        }
                    }
                }
                else
                {
                    if (TraceLevel >= 1)
                    {
                        Console.WriteLine("// Marking label '{0}' as exit label", onlyRecursiveExitTarget);
                    }

                    lgs.ExitLabel = newExitLabel;
                    MadeChanges   = true;
                }
            }

            if ((lgs.ExitLabel != null) && (lgs.Labels.Count > 1))
            {
                ExtractExitLabel(lgs);
            }

            LabelGroupStack.Pop();
        }
Exemplo n.º 9
0
        private void ExtractExitLabel(JSLabelGroupStatement lgs)
        {
            var exitLabel         = lgs.ExitLabel;
            var originalLabelName = exitLabel.Label;

            if (exitLabel.AllChildrenRecursive.OfType <JSGotoExpression>().Any())
            {
                if (TraceLevel >= 1)
                {
                    Console.WriteLine("// Cannot extract exit label '{0}' from label group because it contains a goto or exit", originalLabelName);
                }

                return;
            }

            // The label before this label may have fallen through, so we need to append an ExitLabelGroup
            var previousLabel = lgs.BeforeExitLabel;

            if (previousLabel != null)
            {
                var exitStatement = new JSExpressionStatement(new JSExitLabelGroupExpression(lgs));

                var previousBlock = previousLabel as JSBlockStatement;
                if (previousBlock != null)
                {
                    previousBlock.Statements.Add(exitStatement);
                }
                else
                {
                    var replacement = new JSBlockStatement(
                        previousLabel, exitStatement
                        );

                    replacement.Label         = previousLabel.Label;
                    replacement.IsControlFlow = true;
                    previousLabel.Label       = null;

                    lgs.ReplaceChild(previousLabel, replacement);
                }
            }

            lgs.Labels.Remove(originalLabelName);
            exitLabel.Label         = null;
            exitLabel.IsControlFlow = false;

            {
                var replacement = new JSBlockStatement(
                    lgs,
                    exitLabel
                    );

                exitLabel.OriginalLabel = originalLabelName;

                // Extract the exit label so it directly follows the label group
                ParentNode.ReplaceChild(lgs, replacement);

                // Find and convert all the gotos so that they instead break out of the label group
                var gotos = DeoptimizeSwitchStatements.FindGotos(lgs, originalLabelName);
                foreach (var g in gotos)
                {
                    lgs.ReplaceChildRecursive(g, new JSExitLabelGroupExpression(lgs));
                }
            }

            if (TraceLevel >= 1)
            {
                Console.WriteLine("// Extracted exit label '{0}' from label group", originalLabelName);
            }
            MadeChanges = true;
        }
Exemplo n.º 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)
                    };
                    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);
                                }
                                // 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;
                                }
                            }
                        }

                        // 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);
                    }
                }
            }
Exemplo n.º 11
0
        public void VisitNode(JSLabelGroupStatement lgs)
        {
            Formatter.ConditionalNewLine();
            Formatter.NewLine();
            var labelName = "labelgroup_" + lgs.GroupIndex;

            var firstLabel = lgs.Labels.First().Key;

            foreach (var kvp in lgs.Labels)
            {
                Labels.Add(kvp.Key, new LabelInfo(lgs.GroupIndex, Labels.Count));
            }

            Comment("LabelGroup {0} (starting at {1})", lgs.GroupIndex, firstLabel);
            SetCurrentLabel(firstLabel, lgs.GroupIndex);
            Formatter.NewLine();

            Formatter.WriteSExpr(
                "label", (__) => {
                __.WriteRaw("${0} ", labelName);

                // HACK
                __.Unindent();

                __.WriteSExpr(
                    "loop", (_) => {
                    _.WriteRaw("(label $labelgroup_{0}_dispatch ", lgs.GroupIndex);
                    _.NewLine();

                    foreach (var kvp in lgs.Labels)
                    {
                        var labelInfo = GetLabelInfo(kvp.Key);

                        _.ConditionalNewLine();
                        Comment("Begin Label {1}", lgs.GroupIndex, kvp.Key);

                        _.WriteRaw("(if (i32.eq (get_local $currentLabel_{0}) (i32.const {1})) ", labelInfo.GroupIndex, labelInfo.LabelIndex);
                        _.Indent();
                        _.NewLine();

                        Visit(kvp.Value);
                        _.ConditionalNewLine();
                        _.NewLine();

                        _.Unindent();
                        _.WriteRaw(")");
                        _.NewLine();
                        Comment("End Label {1}", lgs.GroupIndex, kvp.Key);
                        _.NewLine();
                    }

                    _.ConditionalNewLine();
                    Comment("Fallthrough exit from labelgroup {0}", lgs.GroupIndex);
                    _.WriteRaw("(break $labelgroup_{0})", lgs.GroupIndex);
                    _.NewLine();

                    _.ConditionalNewLine();
                    _.WriteRaw(")", lgs.GroupIndex);
                    _.NewLine();
                }
                    );

                // HACK
                __.Indent();
            }
                );
        }
Exemplo n.º 12
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");
                    }
                }
            }
Exemplo n.º 13
0
        public void VisitNode(JSLabelGroupStatement labelGroup)
        {
            Output.NewLine();

            var stepLabel  = String.Format("$labelgroup{0}", labelGroup.GroupIndex);
            var labelVar   = String.Format("$label{0}", labelGroup.GroupIndex);
            var firstLabel = labelGroup.Labels.First().Key;

            Output.WriteRaw("var");
            Output.Space();
            Output.Identifier(labelVar);
            Output.WriteRaw(" = ");
            Output.Value(firstLabel);
            Output.Semicolon();

            Output.Label(stepLabel);
            Output.WriteRaw("while");
            Output.Space();
            Output.LPar();

            Output.WriteRaw("true");

            Output.RPar();
            Output.Space();
            Output.OpenBrace();

            Output.WriteRaw("switch");
            Output.Space();
            Output.LPar();

            Output.Identifier(labelVar);

            Output.RPar();
            Output.Space();
            Output.OpenBrace();

            bool isFirst = true;
            Func <string, bool> emitGoto = (labelName) => {
                if (labelName != null)
                {
                    if (!labelGroup.Labels.ContainsKey(labelName))
                    {
                        return(false);
                    }

                    Output.Identifier(labelVar);
                    Output.WriteRaw(" = ");
                    Output.Value(labelName);
                    Output.Semicolon();
                }

                Output.WriteRaw("continue");
                Output.Space();
                Output.Identifier(stepLabel);

                return(true);
            };

            GotoStack.Push(emitGoto);

            bool needsTrailingBreak = true;

            foreach (var kvp in labelGroup.Labels)
            {
                if (!isFirst && needsTrailingBreak)
                {
                    Output.Indent();
                    emitGoto(kvp.Key);
                    Output.Semicolon(true);
                    Output.Unindent();
                }

                Output.WriteRaw("case");
                Output.Space();
                Output.Value(kvp.Key);
                Output.WriteRaw(":");
                Output.Indent();
                Output.NewLine();

                Visit(kvp.Value);

                Func <JSNode, bool> isNotNull = (n) => {
                    if (n.IsNull)
                    {
                        return(false);
                    }
                    if (n is JSNullStatement)
                    {
                        return(false);
                    }
                    if (n is JSNullExpression)
                    {
                        return(false);
                    }

                    var es = n as JSExpressionStatement;
                    if (es != null)
                    {
                        if (es.Expression.IsNull)
                        {
                            return(false);
                        }
                        if (es.Expression is JSNullExpression)
                        {
                            return(false);
                        }
                    }

                    return(true);
                };

                var nonNullChildren = kvp.Value.Children.Where(isNotNull);

                var lastStatement = nonNullChildren.LastOrDefault();
                JSBlockStatement lastBlockStatement;

                while ((lastBlockStatement = lastStatement as JSBlockStatement) != null)
                {
                    if (lastBlockStatement.IsControlFlow)
                    {
                        break;
                    }
                    else
                    {
                        nonNullChildren = lastStatement.Children.Where(isNotNull);
                        lastStatement   = nonNullChildren.LastOrDefault();
                    }
                }

                var lastExpressionStatement = lastStatement as JSExpressionStatement;

                if (
                    (lastExpressionStatement != null) &&
                    (
                        (lastExpressionStatement.Expression is JSContinueExpression) ||
                        (lastExpressionStatement.Expression is JSBreakExpression) ||
                        (lastExpressionStatement.Expression is JSGotoExpression)
                    )
                    )
                {
                    needsTrailingBreak = false;
                }
                else
                {
                    needsTrailingBreak = true;
                }

                isFirst = false;

                Output.Unindent();

                Output.NewLine();
            }

            GotoStack.Pop();

            if (needsTrailingBreak)
            {
                Output.Indent();
                Output.WriteRaw("break");
                Output.Space();
                Output.Identifier(stepLabel);
                Output.Semicolon(true);
                Output.Unindent();
            }

            Output.CloseBrace();

            Output.CloseBrace();
        }