コード例 #1
0
ファイル: LabelGroupBuilder.cs プロジェクト: robterrell/JSIL
        public void VisitNode(JSWhileLoop wl)
        {
            CheckLabel(wl);

            BlockStack.Push(new EnclosingBlockEntry {
                Block = wl,
                ParentNode = ParentNode,
                Depth = BlockStack.Count
            });

            try {
                VisitChildren(wl);
            } finally {
                BlockStack.Pop();
            }
        }
コード例 #2
0
        public void VisitNode(JSWhileLoop wl)
        {
            var condInvocation = wl.Condition as JSInvocationExpression;
            JSVariable enumeratorVariable;

            if (
                (condInvocation != null) &&
                (condInvocation.JSMethod != null) &&
                (condInvocation.JSMethod.Identifier == "MoveNext") &&
                (condInvocation.JSMethod.Method.DeclaringType.Interfaces.Any((ii) => ii.Item1.FullName == "System.Collections.IEnumerator")) &&
                ((enumeratorVariable = condInvocation.ThisReference as JSVariable) != null)
            ) {
                var enumeratorType = condInvocation.JSMethod.Method.DeclaringType;

                while (EnableEnumeratorRemoval) {
                    var enumeratorAssignmentBeforeLoop = (
                        from boe in SeenAssignments
                        let boeLeftVar = (boe.Left as JSVariable)
                        where (boeLeftVar != null) && (boeLeftVar.Name == enumeratorVariable.Name)
                        select boe
                    ).LastOrDefault();

                    if (enumeratorAssignmentBeforeLoop == null)
                        break;

                    var enumeratorValue = enumeratorAssignmentBeforeLoop.Right;
                    var assignmentInvocation = enumeratorValue as JSInvocationExpression;
                    if (assignmentInvocation == null) {
                        var rre = enumeratorValue as JSResultReferenceExpression;
                        if (rre != null)
                            assignmentInvocation = rre.Referent as JSInvocationExpression;
                    }

                    if (assignmentInvocation == null)
                        break;

                    var jsm = assignmentInvocation.JSMethod;
                    if (jsm == null)
                        break;

                    var attrParams2 = jsm.Method.Metadata.GetAttributeParameters("JSIL.Meta.JSUnderlyingArray");
                    if (attrParams2 != null) {
                        var arrayMember = (string)attrParams2[0].Value;
                        var lengthMember = (string)attrParams2[1].Value;

                        var replacement = ReplaceWhileLoopAndEnumerator(
                            wl, assignmentInvocation.ThisReference,
                            condInvocation.ThisReference, condInvocation.JSMethod.Method.DeclaringType,
                            arrayMember, lengthMember
                        );
                        ParentNode.ReplaceChild(wl, replacement);

                        EnumeratorsToKill.Add(enumeratorVariable);

                        VisitReplacement(replacement);

                        return;
                    }

                    break;
                }

                var attrParams = enumeratorType.Metadata.GetAttributeParameters("JSIL.Meta.JSIsArrayEnumerator");

                if (attrParams != null) {
                    var arrayMember = (string)attrParams[0].Value;
                    var indexMember = (string)attrParams[1].Value;
                    var lengthMember = (string)attrParams[2].Value;

                    var replacement = ReplaceWhileLoop(
                        wl, condInvocation.ThisReference, condInvocation.JSMethod.Method.DeclaringType,
                        arrayMember, indexMember, lengthMember
                    );
                    ParentNode.ReplaceChild(wl, replacement);

                    VisitReplacement(replacement);

                    return;
                }
            }

            VisitChildren(wl);
        }
コード例 #3
0
        private JSForLoop ReplaceWhileLoopAndEnumerator(JSWhileLoop wl, JSExpression backingStore, JSExpression enumerator, TypeInfo enumeratorType, string arrayMember, string lengthMember)
        {
            var loopId = _NextLoopId++;
            var arrayVariableName = String.Format("a${0:x}", loopId);
            var indexVariableName = String.Format("i${0:x}", loopId);
            var lengthVariableName = String.Format("l${0:x}", loopId);

            var currentPropertyReference = enumeratorType.Definition.Properties.First((p) => p.Name == "Current");
            var currentPropertyInfo = enumeratorType.Source.GetProperty(currentPropertyReference);

            var itemType = currentPropertyInfo.ReturnType;
            var arrayType = new ArrayType(itemType);

            var arrayVariable = new JSVariable(
                arrayVariableName, arrayType, Function.Method.Reference,
                JSDotExpression.New(backingStore, new JSStringIdentifier(arrayMember, arrayType))
            );
            var indexVariable = new JSVariable(
                indexVariableName, TypeSystem.Int32, Function.Method.Reference,
                JSLiteral.New(0)
            );
            var lengthVariable = new JSVariable(
                lengthVariableName, TypeSystem.Int32, Function.Method.Reference,
                JSDotExpression.New(backingStore, new JSStringIdentifier(lengthMember, TypeSystem.Int32))
            );

            var initializer = new JSVariableDeclarationStatement(
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, arrayVariable, arrayVariable.DefaultValue, arrayVariable.IdentifierType
                ),
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, indexVariable, indexVariable.DefaultValue, indexVariable.IdentifierType
                ),
                new JSBinaryOperatorExpression(
                    JSOperator.Assignment, lengthVariable, lengthVariable.DefaultValue, lengthVariable.IdentifierType
                )
            );

            var condition = new JSBinaryOperatorExpression(
                JSBinaryOperator.LessThan,
                indexVariable, lengthVariable, TypeSystem.Boolean
            );

            var increment = new JSUnaryOperatorExpression(
                JSUnaryOperator.PostIncrement,
                indexVariable, TypeSystem.Int32
            );

            var result = new JSForLoop(
                initializer, condition, new JSExpressionStatement(increment),
                wl.Statements.ToArray()
            );
            result.Index = wl.Index;

            new PropertyAccessReplacer(
                enumerator, new JSProperty(currentPropertyReference, currentPropertyInfo),
                new JSIndexerExpression(
                    arrayVariable, indexVariable,
                    itemType
                )
            ).Visit(result);

            return result;
        }
コード例 #4
0
        public JSWhileLoop TranslateNode(ILWhileLoop loop)
        {
            JSExpression condition;
            if (loop.Condition != null)
                condition = TranslateNode(loop.Condition);
            else
                condition = JSLiteral.New(true);

            var result = new JSWhileLoop(condition);
            result.Label = String.Format("__loop{0}__", UnlabelledBlockCount++);
            Blocks.Push(result);

            var body = TranslateNode(loop.BodyBlock);

            Blocks.Pop();
            result.Statements.Add(body);
            return result;
        }
コード例 #5
0
ファイル: SimplifyLoops.cs プロジェクト: robashton/JSIL
        public void VisitNode(JSWhileLoop whileLoop)
        {
            JSVariable initVariable = null, lastVariable = null;
            JSBinaryOperator initOperator = null;
            JSExpression initValue = null;

            var prevEStmt = PreviousSibling as JSExpressionStatement;
            var prevVDS = PreviousSibling as JSVariableDeclarationStatement;

            if (prevEStmt != null) {
                var boe = prevEStmt.Expression as JSBinaryOperatorExpression;
                if (
                    (boe != null) &&
                    (boe.Operator is JSAssignmentOperator) &&
                    (boe.Left is JSVariable)
                ) {
                    initVariable = (JSVariable)boe.Left;
                    initOperator = boe.Operator;
                    initValue = boe.Right;
                }
            } else if (prevVDS != null) {
                var decl = prevVDS.Declarations.FirstOrDefault(
                    (d) => !d.IsNull
                );
                if (decl != null) {
                    initVariable = (JSVariable)decl.Left;
                    initOperator = decl.Operator;
                    initValue = decl.Right;
                }
            }

            var lastStatement = whileLoop.Statements.LastOrDefault();
            while ((lastStatement != null) && (lastStatement.GetType() == typeof(JSBlockStatement)))
                lastStatement = ((JSBlockStatement)lastStatement).Statements.LastOrDefault();

            var lastExpressionStatement = lastStatement as JSExpressionStatement;
            if (lastExpressionStatement != null) {
                var lastUoe = lastExpressionStatement.Expression as JSUnaryOperatorExpression;
                var lastBoe = lastExpressionStatement.Expression as JSBinaryOperatorExpression;

                if ((lastUoe != null) && (lastUoe.Operator is JSUnaryMutationOperator)) {
                    lastVariable = lastUoe.Expression as JSVariable;
                } else if ((lastBoe != null) && (lastBoe.Operator is JSAssignmentOperator)) {
                    lastVariable = lastBoe.Left as JSVariable;
                    if (
                        (lastVariable != null) &&
                        !lastBoe.Right.AllChildrenRecursive.Any(
                            (n) => lastVariable.Equals(n)
                        )
                    ) {
                        lastVariable = null;
                    }
                }
            }

            var lastIfStatement = lastStatement as JSIfStatement;
            if (
                (lastIfStatement != null) &&
                whileLoop.Condition is JSBooleanLiteral &&
                ((JSBooleanLiteral)whileLoop.Condition).Value
            ) {
                var innerStatement = lastIfStatement.TrueClause;
                while (innerStatement is JSBlockStatement) {
                    var bs = (JSBlockStatement)innerStatement;
                    if (bs.Statements.Count != 1) {
                        innerStatement = null;
                        break;
                    }

                    innerStatement = bs.Statements[0];
                }

                var eStmt = innerStatement as JSExpressionStatement;

                if (eStmt != null) {
                    var breakExpr = eStmt.Expression as JSBreakExpression;
                    if ((breakExpr != null) && (breakExpr.TargetLabel == whileLoop.Label)) {
                        whileLoop.ReplaceChildRecursive(lastIfStatement, new JSNullStatement());

                        var doLoop = new JSDoLoop(
                            new JSUnaryOperatorExpression(JSOperator.LogicalNot, lastIfStatement.Condition),
                            whileLoop.Statements.ToArray()
                        );
                        doLoop.Label = whileLoop.Label;

                        ParentNode.ReplaceChild(whileLoop, doLoop);
                        VisitChildren(doLoop);
                        return;
                    }
                }
            }

            bool cantBeFor = false;

            if ((initVariable != null) && (lastVariable != null) &&
                !initVariable.Equals(lastVariable)
            ) {
                cantBeFor = true;
            } else if ((initVariable ?? lastVariable) == null) {
                cantBeFor = true;
            } else if (!whileLoop.Condition.AllChildrenRecursive.Any(
                    (n) => (initVariable ?? lastVariable).Equals(n)
            )) {
                cantBeFor = true;
            }

            if (!cantBeFor) {
                JSStatement initializer = null, increment = null;

                if (initVariable != null) {
                    initializer = PreviousSibling as JSStatement;

                    ParentNode.ReplaceChild(PreviousSibling, new JSNullStatement());
                }

                if (lastVariable != null) {
                    increment = lastExpressionStatement;

                    whileLoop.ReplaceChildRecursive(lastExpressionStatement, new JSNullStatement());
                }

                var forLoop = new JSForLoop(
                    initializer, whileLoop.Condition, increment,
                    whileLoop.Statements.ToArray()
                );
                forLoop.Label = whileLoop.Label;

                ParentNode.ReplaceChild(whileLoop, forLoop);
                VisitChildren(forLoop);
            } else {
                VisitChildren(whileLoop);
            }
        }
コード例 #6
0
        public void VisitNode(JSWhileLoop wl)
        {
            var condInvocation = wl.Condition as JSInvocationExpression;
            JSVariable enumeratorVariable;

            if (
                (condInvocation != null) &&
                (condInvocation.JSMethod != null) &&
                (condInvocation.JSMethod.Identifier == "MoveNext") &&
                (condInvocation.JSMethod.Method.DeclaringType.Interfaces.Any((ii) => ii.Item1.FullName == "System.Collections.IEnumerator")) &&
                ((enumeratorVariable = condInvocation.ThisReference as JSVariable) != null)
            ) {
                var enumeratorType = condInvocation.JSMethod.Method.DeclaringType;

                while (EnableEnumeratorRemoval) {
                    var firstPass = FunctionSource.GetFirstPass(Function.Method.QualifiedIdentifier);
                    if (firstPass == null)
                        break;

                    var enumeratorAssignments = (from a in firstPass.Assignments where a.Target.Name == enumeratorVariable.Name select a).ToArray();
                    if (enumeratorAssignments.Length != 1)
                        break;

                    var enumeratorValue = enumeratorAssignments[0].NewValue;
                    var assignmentInvocation = enumeratorValue as JSInvocationExpression;
                    if (assignmentInvocation == null) {
                        var rre = enumeratorValue as JSResultReferenceExpression;
                        if (rre != null)
                            assignmentInvocation = rre.Referent as JSInvocationExpression;
                    }

                    if (assignmentInvocation == null)
                        break;

                    var jsm = assignmentInvocation.JSMethod;
                    if (jsm == null)
                        break;

                    var attrParams2 = jsm.Method.Metadata.GetAttributeParameters("JSIL.Meta.JSUnderlyingArray");
                    if (attrParams2 != null) {
                        var arrayMember = (string)attrParams2[0].Value;
                        var lengthMember = (string)attrParams2[1].Value;

                        var replacement = ReplaceWhileLoopAndEnumerator(
                            wl, assignmentInvocation.ThisReference,
                            condInvocation.ThisReference, condInvocation.JSMethod.Method.DeclaringType,
                            arrayMember, lengthMember
                        );
                        ParentNode.ReplaceChild(wl, replacement);

                        new VariableEliminator(enumeratorVariable, new JSNullExpression()).Visit(Function);

                        VisitReplacement(replacement);
                    }

                    break;
                }

                var attrParams = enumeratorType.Metadata.GetAttributeParameters("JSIL.Meta.JSIsArrayEnumerator");

                if (attrParams != null) {
                    var arrayMember = (string)attrParams[0].Value;
                    var indexMember = (string)attrParams[1].Value;
                    var lengthMember = (string)attrParams[2].Value;

                    var replacement = ReplaceWhileLoop(
                        wl, condInvocation.ThisReference, condInvocation.JSMethod.Method.DeclaringType,
                        arrayMember, indexMember, lengthMember
                    );
                    ParentNode.ReplaceChild(wl, replacement);

                    VisitReplacement(replacement);

                    return;
                }
            }

            VisitChildren(wl);
        }