Exemple #1
0
        internal JSFunctionExpression Create(
            MethodInfo info, MethodDefinition methodDef, MethodReference method,
            QualifiedMemberIdentifier identifier, ILBlockTranslator translator,
            IEnumerable <JSVariable> parameters, JSBlockStatement body
            )
        {
            return(Cache.GetOrCreate(identifier, () => {
                var result = new JSFunctionExpression(
                    new JSMethod(method, info, MethodTypes),
                    translator.Variables,
                    parameters,
                    body,
                    MethodTypes
                    );

                OptimizationQueue.TryEnqueue(identifier);

                return new Entry {
                    Identifier = identifier,
                    Info = info,
                    Reference = method,
                    Expression = result,
                    Variables = translator.Variables,
                    ParameterNames = translator.ParameterNames,
                    SpecialIdentifiers = translator.SpecialIdentifiers
                };
            }).Expression);
        }
        protected void TransformParameterIntoReference(JSVariable parameter, JSBlockStatement block)
        {
            var newParameter   = new JSParameter("$" + parameter.Identifier, parameter.IdentifierType, parameter.Function);
            var newVariable    = new JSVariable(parameter.Identifier, new ByReferenceType(parameter.IdentifierType), parameter.Function);
            var newDeclaration = new JSVariableDeclarationStatement(
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment,
                    // We have to use parameter here, not newVariable or newParameter, otherwise the resulting
                    // assignment looks like 'x.value = initializer' instead of 'x = initializer'
                    parameter,
                    JSIL.NewReference(newParameter),
                    newVariable.IdentifierType
                    )
                );

            if (Tracing)
            {
                Console.WriteLine(String.Format("Transformed {0} into {1}={2}", parameter, newVariable, newParameter));
            }

            Variables[newVariable.Identifier] = newVariable;
            Variables.Add(newParameter.Identifier, newParameter);

            var enclosingFunction = Stack.OfType <JSFunctionExpression>().First();

            enclosingFunction.Body.Statements.Insert(0, newDeclaration);

            var oldIndex = Array.IndexOf(enclosingFunction.Parameters, parameter);

            enclosingFunction.Parameters[oldIndex] = newParameter;
        }
Exemple #3
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");
                    }
                }
            }
Exemple #4
0
        public void NodeSelfAndChildrenRecursive () {
            var fl3 = new JSForLoop(
                new JSNullStatement(), new JSNullExpression(), new JSNullStatement(),
                new JSExpressionStatement(new JSStringIdentifier("loop3 iteration"))
            );
            fl3.Index = 2;

            var fl2 = new JSForLoop(
                new JSNullStatement(), new JSNullExpression(), new JSNullStatement(),
                new JSExpressionStatement(new JSStringIdentifier("loop2 iteration"))
            );
            fl2.Index = 1;

            var fl1 = new JSForLoop(
                new JSNullStatement(), new JSNullExpression(), new JSNullStatement(),
                fl2
            );
            fl1.Index = 0;

            var tree = new JSBlockStatement(
                fl1,
                fl3
            );

            DumpNodeSequence(tree.SelfAndChildrenRecursive);
        }
        public void VisitNode(JSBlockStatement block)
        {
            SeenRetargetsInScope.Push(new Dictionary <RetargetKey, int>());
            ScopeNodeIndices.Push(NodeIndex);

            VisitChildren(block);

            SeenRetargetsInScope.Pop();
            ScopeNodeIndices.Pop();
        }
Exemple #6
0
        public void VisitNode(JSBlockStatement bs)
        {
            CheckLabel(bs);

            PushBlock(bs);

            try {
                VisitChildren(bs);
            } finally {
                BlockStack.Pop();
            }
        }
Exemple #7
0
        internal JSFunctionExpression Create(
            MethodInfo info, MethodDefinition methodDef, MethodReference method,
            QualifiedMemberIdentifier identifier, ILBlockTranslator translator,
            JSVariable[] parameters, JSBlockStatement body
            )
        {
            var args = new PopulatedCacheEntryArgs {
                Info       = info,
                Method     = method,
                Translator = translator,
                Parameters = parameters,
                Body       = body,
            };

            return(Cache.GetOrCreate(identifier, args, MakePopulatedCacheEntry).Expression);
        }
Exemple #8
0
        public void VisitNode(JSBlockStatement block, bool includeBraces)
        {
            if (includeBraces)
            {
                Output.OpenBrace();
            }

            for (var i = 0; i < block.Statements.Count; i++)
            {
                Visit(block.Statements[i]);
            }

            if (includeBraces)
            {
                Output.CloseBrace();
            }
        }
Exemple #9
0
        public void VisitNode(JSBlockStatement bs)
        {
            RemoveNullStatements(bs);

            if ((bs.Statements.Count == 0) && (bs.Label == null))
            {
                var newNull = new JSNullStatement();
                ParentNode.ReplaceChild(bs, newNull);
                VisitReplacement(newNull);
                return;
            }

            VisitChildren(bs);

            // Some of the children may have replaced themselves with nulls
            RemoveNullStatements(bs);
        }
Exemple #10
0
        public void VisitNode(JSBlockStatement bs)
        {
            CheckForFallthrough(bs);

            var lastSwitchCase = LastSwitchCase;
            var thisSwitchCase = ParentSwitchCase;

            LastSwitchCase = thisSwitchCase;

            var parentLabelGroup = ParentNode as JSLabelGroupStatement;
            var isControlFlow    = bs.IsControlFlow ||
                                   (thisSwitchCase != lastSwitchCase) ||
                                   (parentLabelGroup != null);

            if (TraceLevel >= 3)
            {
                Console.WriteLine("// Entering block {0}", bs.Label ?? bs.GetType().Name);
            }

            if (isControlFlow)
            {
                if (TraceLevel >= 3)
                {
                    Console.WriteLine("// Count reset");
                }

                AbsoluteJumpsSeenStack.Add(0);
            }

            BlockStack.Push(bs);

            VisitChildren(bs);

            BlockStack.Pop();

            if (TraceLevel >= 3)
            {
                Console.WriteLine("// Exiting block");
            }

            if (isControlFlow)
            {
                AbsoluteJumpsSeenStack.RemoveAt(AbsoluteJumpsSeenStack.Count - 1);
            }
        }
Exemple #11
0
        protected void RemoveNullStatements(JSBlockStatement bs)
        {
            bs.Statements.RemoveAll(
                (s) => {
                var es = s as JSExpressionStatement;
                if ((es != null) && es.Expression.IsNull)
                {
                    return(true);
                }

                if (s.IsNull)
                {
                    return(true);
                }

                return(false);
            }
                );
        }
Exemple #12
0
 public void VisitNode(JSBlockStatement block)
 {
     VisitNode(block, false);
 }
Exemple #13
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;
        }
        protected void TransformVariableIntoReference(JSVariable variable, JSVariableDeclarationStatement statement, int declarationIndex, JSBlockStatement enclosingBlock)
        {
            var oldDeclaration    = statement.Declarations[declarationIndex];
            var valueType         = oldDeclaration.Right.GetActualType(JSIL.TypeSystem);
            var newVariable       = variable.Reference();
            var enclosingFunction = Stack.OfType <JSFunctionExpression>().First();

            JSExpression initialValue;

            // If the declaration was in function scope originally we can hoist the initial value
            //  into our new variable declaration. If not, we need to initialize the ref variable
            //  to the default value for its type. It will get the correct value assigned later.
            if (enclosingBlock == enclosingFunction.Body)
            {
                initialValue = oldDeclaration.Right;
            }
            else
            {
                initialValue = new JSDefaultValueLiteral(valueType);
            }

            var newDeclaration = new JSVariableDeclarationStatement(new JSBinaryOperatorExpression(
                                                                        JSOperator.Assignment,
                                                                        // We have to use a constructed ref to the variable here, otherwise
                                                                        //  the declaration will look like 'var x.value = foo'
                                                                        new JSVariable(variable.Identifier, variable.IdentifierType, variable.Function),
                                                                        JSIL.NewReference(initialValue),
                                                                        newVariable.IdentifierType
                                                                        ));

            if (Tracing)
            {
                Console.WriteLine(String.Format("Transformed {0} into {1} in {2}", variable, newVariable, statement));
            }

            // Insert the new declaration directly before the top-level block containing the original
            //  declaration. This ensures that if its initial value has a dependency on external state,
            //  the declaration will not precede the values it depends on.
            // Note that for declarations that were hoisted out of inner blocks (conditionals, loops)
            //  it doesn't actually matter where the insert occurs, since we initialize with a default
            //  value in that case.
            enclosingFunction.Body.InsertNearChildRecursive(
                statement, newDeclaration, 0
                );

            // If the reference is being declared in function scope, it doesn't need a separate assignment
            //  for its initialization. Otherwise, we need to insert an assignment after the original variable
            //  declaration statement to ensure that the reference variable is initialized to the right value
            //  at the exact right point in the function's execution.
            if (enclosingBlock != enclosingFunction.Body)
            {
                var newAssignment = new JSExpressionStatement(
                    new JSBinaryOperatorExpression(
                        JSOperator.Assignment, newVariable, oldDeclaration.Right, valueType
                        )
                    );
                var insertLocation = enclosingBlock.Statements.IndexOf(statement) + 1;
                enclosingBlock.Statements.Insert(insertLocation, newAssignment);
            }

            Variables[variable.Identifier] = newVariable;
            statement.Declarations.RemoveAt(declarationIndex);
            TransformedVariables.Add(variable.Identifier);
        }
Exemple #15
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");
                    }
                }
            }
Exemple #16
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);
                    }
                }
            }
Exemple #17
0
        public void VisitNode(JSBlockStatement bs)
        {
            MaybeHoist(bs, bs.Children.OfType <JSStatement>());

            VisitChildren(bs);
        }
        public void VisitNode(JSSwitchStatement ss)
        {
            IndexLookup indexLookup;
            Initializer initializer;
            NullCheck   nullCheck;

            // Detect switch statements using a lookup dictionary
            var switchVar = ss.Condition as JSVariable;

            if (
                (switchVar != null) &&
                IndexLookups.TryGetValue(switchVar, out indexLookup) &&
                Initializers.TryGetValue(indexLookup.Field, out initializer)
                )
            {
                if (NullChecks.TryGetValue(indexLookup.SwitchVariable, out nullCheck))
                {
                    ParentNode.ReplaceChild(nullCheck.Statement, new JSNullStatement());
                }

                Stack.Skip(2).First().ReplaceChildRecursive(initializer.Statement, new JSNullStatement());

                if (indexLookup.IsInverted)
                {
                    ParentNode.ReplaceChild(indexLookup.Statement, new JSNullStatement());
                }

                var            switchCases = new List <JSSwitchCase>();
                JSExpression[] values;
                foreach (var cse in ss.Cases)
                {
                    var body = cse.Body;

                    if (cse.Values == null)
                    {
                        values = null;
                        body   = new JSBlockStatement(body.Statements.ToArray());
                    }
                    else
                    {
                        values = (from v in cse.Values
                                  let il = v as JSIntegerLiteral
                                           where il != null
                                           select initializer.Values[(int)il.Value]).ToArray();
                    }

                    switchCases.Add(new JSSwitchCase(
                                        values, body
                                        ));
                }

                var newSwitch = new JSSwitchStatement(
                    indexLookup.SwitchVariable, switchCases.ToArray()
                    );

                SwitchStatementsDeoptimized += 1;

                ParentNode.ReplaceChild(ss, newSwitch);

                var outVar = indexLookup.OutputVariable;
                foreach (var fn in Stack.OfType <JSFunctionExpression>())
                {
                    foreach (var vds in fn.Body.AllChildrenRecursive.OfType <JSVariableDeclarationStatement>().ToArray())
                    {
                        for (int i = 0, c = vds.Declarations.Count; i < c; i++)
                        {
                            var leftVar = vds.Declarations[i].Left as JSVariable;

                            if ((leftVar != null) && (leftVar.Identifier == outVar.Identifier))
                            {
                                vds.Declarations.RemoveAt(i);
                                i--;
                                c--;
                            }
                        }
                    }

                    fn.AllVariables.Remove(outVar.Identifier);
                }

                VisitReplacement(newSwitch);
            }

            VisitChildren(ss);
        }
Exemple #19
0
 public void VisitNode(JSBlockStatement block)
 {
     EmitBlockInterior(block.Statements);
 }