コード例 #1
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) {
#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);
                    }
                }
            }
コード例 #2
0
        public void VisitNode (JSBlockStatement block) {
            SeenRetargetsInScope.Push(new Dictionary<RetargetKey, int>());
            ScopeNodeIndices.Push(NodeIndex);

            VisitChildren(block);

            SeenRetargetsInScope.Pop();
            ScopeNodeIndices.Pop();
        }
コード例 #3
0
ファイル: JSStatementTypes.cs プロジェクト: xen2/JSIL
        public JSSwitchCase(JSExpression[] values, JSBlockStatement body)
        {
            if ((values != null) && (values.Length == 0))
            {
                values = null;
            }

            Values = values;
            Body   = body;
        }
コード例 #4
0
ファイル: JSStatementTypes.cs プロジェクト: dosh1974/JSIL
        public JSSwitchCase(JSExpression[] values, JSBlockStatement body, bool isDefault)
        {
            if ((values != null) && (values.Length == 0))
            {
                values = null;
            }

            Values    = values;
            Body      = body;
            IsDefault = isDefault;
        }
コード例 #5
0
ファイル: CollapseNulls.cs プロジェクト: GlennSandoval/JSIL
        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;
                }
            );
        }
コード例 #6
0
ファイル: CollapseNulls.cs プロジェクト: GlennSandoval/JSIL
        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);
        }
コード例 #7
0
        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)
                Debug.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;
        }
コード例 #8
0
ファイル: FunctionCache.cs プロジェクト: nowonu/JSIL
        internal JSFunctionExpression Create(
            MethodInfo info, MethodDefinition methodDef, MethodReference method, 
            QualifiedMemberIdentifier identifier, ILBlockTranslator translator, 
            IEnumerable<JSVariable> parameters, JSBlockStatement body
        )
        {
            var result = new JSFunctionExpression(
                new JSMethod(method, info),
                translator.Variables,
                parameters,
                body
            );

            var entry = new Entry {
                Identifier = identifier,
                Info = info,
                Reference = method,
                Expression = result,
                Variables = translator.Variables,
                ParameterNames = translator.ParameterNames,
                SpecialIdentifiers = translator.SpecialIdentifiers
            };

            Cache.Add(identifier, entry);
            OptimizationQueue.Add(identifier);

            return result;
        }
コード例 #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;
        }
コード例 #10
0
        public JSTryCatchBlock TranslateNode(ILTryCatchBlock tcb)
        {
            var body = TranslateNode(tcb.TryBlock);
            JSVariable catchVariable = null;
            JSBlockStatement catchBlock = null;
            JSBlockStatement finallyBlock = null;

            if (tcb.CatchBlocks.Count > 0) {
                var pairs = new List<KeyValuePair<JSExpression, JSStatement>>();
                catchVariable = DeclareVariable(new JSExceptionVariable(TypeSystem, ThisMethodReference));

                bool foundUniversalCatch = false;
                foreach (var cb in tcb.CatchBlocks) {
                    JSExpression pairCondition = null;

                    if (
                        (cb.ExceptionType.FullName == "System.Exception") ||
                        (cb.ExceptionType.FullName == "System.Object")
                    ) {
                        // Bad IL sometimes contains entirely meaningless catch clauses. It's best to just ignore them.
                        if (
                            (cb.Body.Count == 1) && (cb.Body[0] is ILExpression) &&
                            (((ILExpression)cb.Body[0]).Code == ILCode.Rethrow)
                        ) {
                            continue;
                        }

                        if (foundUniversalCatch) {
                            Console.Error.WriteLine("Found multiple catch-all catch clauses. Any after the first will be ignored.");
                            continue;
                        }

                        foundUniversalCatch = true;
                    } else {
                        if (foundUniversalCatch)
                            throw new NotImplementedException("Catch-all clause must be last");

                        pairCondition = JSIL.CheckType(catchVariable, cb.ExceptionType);
                    }

                    var pairBody = TranslateBlock(cb.Body);

                    if (cb.ExceptionVariable != null) {
                        var excVariable = DeclareVariable(cb.ExceptionVariable, ThisMethodReference);

                        pairBody.Statements.Insert(
                            0, new JSVariableDeclarationStatement(new JSBinaryOperatorExpression(
                                JSOperator.Assignment, excVariable,
                                catchVariable, cb.ExceptionVariable.Type
                            ))
                        );
                    }

                    pairs.Add(new KeyValuePair<JSExpression, JSStatement>(
                        pairCondition, pairBody
                    ));
                }

                if (!foundUniversalCatch)
                    pairs.Add(new KeyValuePair<JSExpression,JSStatement>(
                        null, new JSExpressionStatement(new JSThrowExpression(catchVariable))
                    ));

                if ((pairs.Count == 1) && (pairs[0].Key == null))
                    catchBlock = new JSBlockStatement(
                        pairs[0].Value
                    );
                else
                    catchBlock = new JSBlockStatement(
                        JSIfStatement.New(pairs.ToArray())
                    );
            }

            if (tcb.FinallyBlock != null)
                finallyBlock = TranslateNode(tcb.FinallyBlock);

            if (tcb.FaultBlock != null) {
                if (catchBlock != null)
                    throw new Exception("A try block cannot have both a catch block and a fault block");

                catchVariable = DeclareVariable(new JSExceptionVariable(TypeSystem, ThisMethodReference));
                catchBlock = new JSBlockStatement(TranslateBlock(tcb.FaultBlock.Body));

                catchBlock.Statements.Add(new JSExpressionStatement(new JSThrowExpression(catchVariable)));
            }

            return new JSTryCatchBlock(
                body, catchVariable, catchBlock, finallyBlock
            );
        }
コード例 #11
0
ファイル: LabelGroupBuilder.cs プロジェクト: KevinKelley/JSIL
            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");
                    }
                }
            }
コード例 #12
0
ファイル: ControlFlowSimplifier.cs プロジェクト: Caspeco/JSIL
        public void VisitNode(JSBlockStatement bs)
        {
            var thisSwitchCase = ParentSwitchCase;
            var parentLabelGroup = ParentNode as JSLabelGroupStatement;
            var isControlFlow = bs.IsControlFlow ||
                (thisSwitchCase != LastSwitchCase) ||
                (parentLabelGroup != null);

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

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

                AbsoluteJumpsSeenStack.Add(0);
            }

            BlockStack.Push(bs);

            VisitChildren(bs);

            BlockStack.Pop();

            if (TraceLevel >= 2)
                Console.WriteLine("// Exiting block");

            if (isControlFlow)
                AbsoluteJumpsSeenStack.RemoveAt(AbsoluteJumpsSeenStack.Count - 1);

            LastSwitchCase = thisSwitchCase;
        }
コード例 #13
0
ファイル: APITests.cs プロジェクト: GlennSandoval/JSIL
        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);
        }
コード例 #14
0
ファイル: LabelGroupBuilder.cs プロジェクト: robterrell/JSIL
            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");
                    }
                }
            }
コード例 #15
0
        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)
                Debug.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);
        }
コード例 #16
0
ファイル: FunctionCache.cs プロジェクト: cbsistem/JSIL
        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;
        }
コード例 #17
0
ファイル: JSStatementTypes.cs プロジェクト: poizan42/JSIL
        public JSSwitchCase(JSExpression[] values, JSBlockStatement body, bool isDefault)
        {
            if ((values != null) && (values.Length == 0))
                values = null;

            Values = values;
            Body = body;
            IsDefault = isDefault;
        }
コード例 #18
0
ファイル: JSStatementTypes.cs プロジェクト: jean80it/JSIL
        public JSSwitchCase(JSExpression[] values, JSBlockStatement body)
        {
            if ((values != null) && (values.Length == 0))
                values = null;

            Values = values;
            Body = body;
        }
コード例 #19
0
ファイル: LabelGroupBuilder.cs プロジェクト: KevinKelley/JSIL
        public void VisitNode(JSBlockStatement bs)
        {
            CheckLabel(bs);

            PushBlock(bs);

            try {
                VisitChildren(bs);
            } finally {
                BlockStack.Pop();
            }
        }
コード例 #20
0
ファイル: ILBlockTranslator.cs プロジェクト: Caspeco/JSIL
        //
        // IL Node Types
        //
        protected JSBlockStatement TranslateBlock(IEnumerable<ILNode> children)
        {
            JSBlockStatement result, currentBlock;

            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;
        }
コード例 #21
0
ファイル: LabelGroupBuilder.cs プロジェクト: KevinKelley/JSIL
        public void VisitNode(JSBlockStatement bs)
        {
            MaybeHoist(bs, bs.Children.OfType<JSStatement>());

            VisitChildren(bs);
        }
コード例 #22
0
        protected void TransformParameterIntoReference(JSVariable parameter, JSBlockStatement block)
        {
            var newParameter = new JSParameter("$" + parameter.Identifier, parameter.Type);
            var newVariable = new JSVariable(parameter.Identifier, new ByReferenceType(parameter.Type));
            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.Type
                )
            );

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

            Variables[newVariable.Identifier] = newVariable;
            Variables.Add(newParameter.Identifier, newParameter);
            ParameterNames.Remove(parameter.Identifier);
            ParameterNames.Add(newParameter.Identifier);
            block.Statements.Insert(0, newDeclaration);
        }