Ejemplo n.º 1
0
        private bool IsVarEffectivelyConstantHere(JSVariable variable)
        {
            if (variable == null)
            {
                return(false);
            }
            if (variable.IsParameter)
            {
                return(false);
            }

            // If we're making a copy of a local variable, and this is the last reference to
            //  the variable, we can eliminate the copy.
            if (
                !SecondPass.Data.VariablesPassedByRef.Contains(variable.Identifier) &&

                SecondPass.Data.Accesses
                .Where(a => a.Source == variable.Identifier)
                // FIXME: This should probably be NodeIndex but that gets out of sync somehow? Outdated analysis data?
                .All(a => a.StatementIndex <= StatementIndex) &&

                SecondPass.Data.Assignments
                .Where(a => a.Target == variable.Identifier)
                // FIXME: This should probably be NodeIndex but that gets out of sync somehow? Outdated analysis data?
                .All(a => a.StatementIndex < StatementIndex)
                )
            {
                return(true);
            }

            return(false);
        }
Ejemplo n.º 2
0
        private IEnumerable <HElement> GetPageContents(SessionData sessionData, string subUrl)
        {
            yield return(new HHeadline("Directoy Responses"));

            if (string.IsNullOrEmpty(subUrl))
            {
                yield return(new HText($"Directoy Responses are called for all request targeting a specific sub-directory like '{URL}/<suburl>' for this {nameof(DirectoryElementResponse)}."));

                yield return(new HText($"Enter a suburl to visit:"));

                // Create a text-field that changes the sub-url, a button should go to on click.
                JSVariable suburl = new JSVariable();
                JSButton   button = new JSButton("Go to Sub-URL");
                button.onclick = new JScript(JSValue.CurrentBrowserURL.Set(new JSStringValue($"{URL}/") + suburl.Name));

                JSInput input = new JSInput(HInput.EInputType.text, "suburl");
                input.onchange = new JScript(suburl.Set(input.GetInnerValue()));

                yield return(new HContainer(new HScript(suburl.GetJsCode(sessionData)), input, button)
                {
                    Class = "fit"
                });
            }
            else
            {
                yield return(new HHeadline($"Sub-URL '{subUrl}' has been called.", 3));

                yield return(new HTextBlock($"You can return to the main-page of this {nameof(DirectoryElementResponse)} by clicking ", new HLink("here", "/" + URL)
                {
                    Style = "display: initial;"
                }, "."));
            }
        }
        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;
        }
Ejemplo n.º 4
0
 public SideEffect(
     int[] parentNodeIndices, int statementIndex, int nodeIndex,
     JSVariable variable
     ) : base(parentNodeIndices, statementIndex, nodeIndex)
 {
     Variable = variable;
 }
Ejemplo n.º 5
0
            public Invocation(
                int[] parentNodeIndices, int statementIndex, int nodeIndex,
                JSVariable thisVariable, JSMethod method, object nonJSMethod,
                IDictionary <string, string[]> variables
                ) : base(parentNodeIndices, statementIndex, nodeIndex)
            {
                if (thisVariable != null)
                {
                    ThisVariable = thisVariable.Identifier;
                }
                else
                {
                    ThisVariable = null;
                }

                ThisType = null;
                Method   = method;
                if (method == null)
                {
                    NonJSMethod = nonJSMethod;
                }
                else
                {
                    NonJSMethod = null;
                }
                Variables = variables;
            }
Ejemplo n.º 6
0
        protected void EliminateVariable(JSNode context, JSVariable variable, JSExpression replaceWith, QualifiedMemberIdentifier method)
        {
            {
                var replacer = new VariableEliminator(
                    variable,
                    JSChangeTypeExpression.New(replaceWith, variable.GetActualType(TypeSystem), TypeSystem)
                    );
                replacer.Visit(context);
            }

            {
                var replacer    = new VariableEliminator(variable, replaceWith);
                var assignments = (from a in FirstPass.Assignments where
                                   variable.Equals(a.NewValue) ||
                                   a.NewValue.SelfAndChildrenRecursive.Any(variable.Equals)
                                   select a).ToArray();

                foreach (var a in assignments)
                {
                    if (!variable.Equals(a.NewValue))
                    {
                        replacer.Visit(a.NewValue);
                    }
                }
            }

            Variables.Remove(variable.Identifier);
            FunctionSource.InvalidateFirstPass(method);
        }
Ejemplo n.º 7
0
 public Access(
     int[] parentNodeIndices, int statementIndex, int nodeIndex,
     JSVariable source, bool isControlFlow
     ) : base(parentNodeIndices, statementIndex, nodeIndex)
 {
     Source        = source;
     IsControlFlow = isControlFlow;
 }
Ejemplo n.º 8
0
 public SlotFlags this[JSVariable v] {
     get {
         return(this[v.Name]);
     }
     set {
         this[v.Name] = value;
     }
 }
Ejemplo n.º 9
0
 public Invocation(int statementIndex, int nodeIndex, JSVariable thisVariable, JSMethod method, IDictionary <string, string[]> variables)
     : base(statementIndex, nodeIndex)
 {
     ThisVariable = thisVariable.Identifier;
     ThisType     = null;
     Method       = method;
     Variables    = variables;
 }
Ejemplo n.º 10
0
 public void VisitNode(JSVariable variable)
 {
     Formatter.WriteSExpr(
         "get_local",
         (_) =>
         _.WriteRaw("${0}", WasmUtil.EscapeIdentifier(variable.Name))
         );
 }
Ejemplo n.º 11
0
        public void VisitNode(JSVariable variable)
        {
            if (variable.IsThis)
            {
                if (ThisReplacementStack.Count > 0)
                {
                    var thisRef = ThisReplacementStack.Peek();
                    if (thisRef != null)
                    {
                        Visit(thisRef);
                    }

                    return;
                }
                else
                {
                    Output.WriteRaw("this");
                }
            }
            else
            {
                Output.Identifier(variable.Identifier);
            }

            // Don't emit .value when initializing a reference in a declaration.
            var boe = ParentNode as JSBinaryOperatorExpression;

            if (
                (boe != null) &&
                (boe.Left == variable) &&
                (Stack.Skip(2).FirstOrDefault() is JSVariableDeclarationStatement)
                )
            {
                return;
            }

            if (variable.IsReference)
            {
                if (variable.IsThis)
                {
                    if (JSExpression.DeReferenceType(variable.Type).IsValueType)
                    {
                        return;
                    }
                    else
                    {
                        throw new InvalidOperationException(String.Format(
                                                                "The this-reference '{0}' was a reference to a non-value type: {1}",
                                                                variable, variable.Type
                                                                ));
                    }
                }

                Output.Dot();
                Output.Identifier("value");
            }
        }
Ejemplo n.º 12
0
 protected void ModifiedVariable(JSVariable variable)
 {
     if (!State.ModificationCount.ContainsKey(variable.Name))
     {
         State.ModificationCount[variable.Name] = 1;
     }
     else
     {
         State.ModificationCount[variable.Name] += 1;
     }
 }
        protected bool MatchesConstructedReference(JSExpression lhs, JSVariable rhs)
        {
            var jsv = lhs as JSVariable;

            if ((jsv != null) && (jsv.Identifier == rhs.Identifier))
            {
                return(true);
            }

            return(false);
        }
Ejemplo n.º 14
0
        protected void AddToList <T> (Dictionary <JSVariable, List <T> > dict, JSVariable variable, T index)
        {
            List <T> list;

            if (!dict.TryGetValue(variable, out list))
            {
                dict[variable] = list = new List <T>();
            }

            list.Add(index);
        }
Ejemplo n.º 15
0
 public Assignment(
     int[] parentNodeIndices, int statementIndex, int nodeIndex,
     JSVariable target, JSExpression newValue,
     JSOperator @operator,
     TypeReference targetType, TypeReference sourceType
     ) : base(parentNodeIndices, statementIndex, nodeIndex)
 {
     Target         = target;
     NewValue       = newValue;
     SourceVariable = newValue as JSVariable;
     SourceType     = sourceType;
     TargetType     = targetType;
     Operator       = @operator;
     IsConversion   = !TypeUtil.TypesAreEqual(targetType, sourceType);
 }
Ejemplo n.º 16
0
        public void VisitNode(JSVariable variable)
        {
            int count;

            if (ReferenceCounts.TryGetValue(variable.Identifier, out count))
            {
                ReferenceCounts[variable.Identifier] = count + 1;
            }
            else
            {
                ReferenceCounts[variable.Identifier] = 1;
            }

            VisitChildren(variable);
        }
Ejemplo n.º 17
0
        public void VisitNode(JSVariable variable)
        {
            if (CurrentName == "FunctionSignature")
            {
                // In argument list
                return;
            }

            if (Variable.Equals(variable))
            {
                ParentNode.ReplaceChild(variable, Replacement);
            }
            else
            {
                VisitChildren(variable);
            }
        }
Ejemplo n.º 18
0
        private JSVariable MakeTemporaryVariable(TypeReference type, out string id, JSExpression defaultValue = null)
        {
            string          _id       = id = string.Format("$hoisted{0:X2}", HoistedVariableCount++);
            MethodReference methodRef = null;

            if (Function.Method != null)
            {
                methodRef = Function.Method.Reference;
            }

            // So introspection knows about it
            var result = new JSVariable(id, type, methodRef);

            Function.AllVariables.Add(_id, result);
            ToDeclare.Add(new PendingDeclaration(id, type, result, defaultValue));

            return(result);
        }
Ejemplo n.º 19
0
        protected void EliminateVariable(JSNode context, JSVariable variable, JSExpression replaceWith, QualifiedMemberIdentifier method)
        {
            {
                var replacer = new VariableEliminator(
                    variable,
                    JSChangeTypeExpression.New(replaceWith, TypeSystem, variable.GetActualType(TypeSystem))
                    );
                replacer.Visit(context);
            }

            {
                var replacer    = new VariableEliminator(variable, replaceWith);
                var assignments = (from a in FirstPass.Assignments where
                                   variable.Equals(a.NewValue) ||
                                   a.NewValue.SelfAndChildrenRecursive.Any((_n) => variable.Equals(_n))
                                   select a).ToArray();

                foreach (var a in assignments)
                {
                    if (variable.Equals(a.NewValue))
                    {
                        FirstPass.Assignments.Remove(a);

                        FirstPass.Assignments.Add(
                            new FunctionAnalysis1stPass.Assignment(
                                a.ParentNodeIndices, a.StatementIndex, a.NodeIndex,
                                a.Target, replaceWith, a.Operator,
                                a.TargetType, a.SourceType
                                )
                            );
                    }
                    else
                    {
                        replacer.Visit(a.NewValue);
                    }
                }
            }

            Variables.Remove(variable.Identifier);
            FunctionSource.InvalidateFirstPass(method);
        }
        public void VisitNode(JSVariable variable)
        {
            if (
                (ParentNode is JSFunctionExpression) &&
                (this.CurrentName == "FunctionSignature")
                )
            {
                VisitChildren(variable);
                return;
            }

            if (
                (variable.Identifier != Variable.Identifier) ||
                // Don't transform if we're inside a read-through already
                (ParentNode is JSReadThroughReferenceExpression) ||
                (
                    // If we're inside a write-through and on the LHS, don't transform
                    (ParentNode is JSWriteThroughReferenceExpression) &&
                    (this.CurrentName == "Left")
                )
                )
            {
                VisitChildren(variable);
                return;
            }

            // If we're inside a pass-by-reference (ref x) then don't transform
            if (
                Stack.OfType <JSPassByReferenceExpression>().Any()
                )
            {
                VisitChildren(variable);
                return;
            }

            var replacement = new JSReadThroughReferenceExpression(variable);

            ParentNode.ReplaceChild(variable, replacement);
            VisitReplacement(replacement);
        }
Ejemplo n.º 21
0
        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.SelfAndChildrenRecursive.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.TargetLoop == whileLoop.Index))
                    {
                        whileLoop.ReplaceChildRecursive(lastIfStatement, new JSNullStatement());

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

                        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.SelfAndChildrenRecursive.Any(
                         (n) => (initVariable ?? lastVariable).Equals(n)
                         ))
            {
                cantBeFor = true;
            }
            else if (
                !PostSwitchTransform && (
                    (lastStatement is JSSwitchStatement) ||
                    (lastStatement is JSLabelGroupStatement)
                    )
                )
            {
                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.Index = whileLoop.Index;

                ParentNode.ReplaceChild(whileLoop, forLoop);
                VisitChildren(forLoop);
            }
            else
            {
                VisitChildren(whileLoop);
            }
        }
Ejemplo n.º 22
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(
                JSOperator.LessThan,
                indexVariable, lengthVariable, TypeSystem.Boolean
                );

            var increment = new JSUnaryOperatorExpression(
                JSOperator.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);
        }
Ejemplo n.º 23
0
        private void EmitFieldIntrinsics(int heapSize)
        {
            // FIXME: Gross
            var tis = (ITypeInfoSource)Translator.TypeInfoProvider;

            Formatter.WriteRaw(";; Compiler-generated field accessors");
            Formatter.NewLine();

            foreach (var kvp in FieldTable.OrderBy(kvp => kvp.Value.Offset))
            {
                var fd         = kvp.Value.Field;
                var fi         = (FieldInfo)tis.Get(fd);
                var name       = WasmUtil.FormatMemberName(fi.Member);
                var typeSystem = fd.FieldType.Module.TypeSystem;

                // HACK
                var baseAddressParam = new JSVariable("address", typeSystem.Int32, null);
                // HACK
                var valueParam = new JSVariable("value", fd.FieldType, null);

                JSExpression address;
                if (fd.IsStatic)
                {
                    address = JSLiteral.New(kvp.Value.Offset + heapSize);
                }
                else
                {
                    address = new JSBinaryOperatorExpression(
                        JSOperator.Add,
                        baseAddressParam,
                        JSLiteral.New(kvp.Value.Offset),
                        typeSystem.Int32
                        );
                }

                Formatter.ConditionalNewLine();
                Formatter.WriteRaw(
                    "(func $__get_{0} (result {1}){2}(return ",
                    name,
                    WasmUtil.PickTypeKeyword(fd.FieldType),
                    fd.IsStatic
                        ? " "
                        : " (param $address i32) "
                    );

                var gm = new GetMemory(
                    fd.FieldType, /* FIXME: Align addresses */ false,
                    address
                    );

                // HACK
                EntryPointAstEmitter.Emit(gm);

                Formatter.WriteRaw(") )");

                if (fd.IsInitOnly)
                {
                    continue;
                }

                Formatter.NewLine();
                Formatter.WriteRaw(
                    "(func $__set_{0}{2}(param $value {1}) ",
                    name,
                    WasmUtil.PickTypeKeyword(fd.FieldType),
                    fd.IsStatic
                        ? " "
                        : " (param $address i32) "
                    );
                Formatter.Indent();
                Formatter.NewLine();
                var sm = new SetMemory(
                    fd.FieldType, /* FIXME: Align addresses */ false,
                    address, valueParam
                    );

                // HACK
                EntryPointAstEmitter.Emit(sm);

                Formatter.Unindent();
                Formatter.ConditionalNewLine();
                Formatter.WriteRaw(")");
            }

            Formatter.NewLine();
            Formatter.NewLine();
        }
 public VariableReferenceAccessTransformer(JSILIdentifier jsil, JSVariable variable)
 {
     JSIL     = jsil;
     Variable = variable;
 }
Ejemplo n.º 25
0
        public void VisitNode(JSVariable v)
        {
            SeenAlready.Add(v);

            VisitChildren(v);
        }
Ejemplo n.º 26
0
        public void VisitNode(JSVariable variable)
        {
            if (CurrentName == "FunctionSignature")
            {
                // In argument list
                VisitChildren(variable);
                return;
            }

            var enclosingStatement            = GetEnclosingNodes <JSStatement>().FirstOrDefault();
            var enclosingAssignmentStatements = GetEnclosingNodes <JSExpressionStatement>(
                (es) => {
                var boe = es.Expression as JSBinaryOperatorExpression;
                if (boe == null)
                {
                    return(false);
                }

                var isAssignment   = boe.Operator == JSOperator.Assignment;
                var leftIsVariable = boe.Left is JSVariable;
                return(isAssignment && leftIsVariable &&
                       (boe.Left.Equals(variable) || boe.Right.Equals(variable)));
            }
                ).ToArray();

            if ((enclosingAssignmentStatements.Length == 0) && (
                    !(enclosingStatement.Node is JSVariableDeclarationStatement)
                    ))
            {
                bool isControlFlow =
                    (
                        (enclosingStatement.Node is JSIfStatement) &&
                        (enclosingStatement.ChildName != "Condition")
                    ) || (
                        (enclosingStatement.Node is JSSwitchStatement) &&
                        (enclosingStatement.ChildName != "Condition")
                        );

                // Don't do the condition check here since a loop's condition can be evaluated multiple times
                var enclosingBlock = enclosingStatement.Node as JSBlockStatement;
                if (enclosingBlock != null)
                {
                    isControlFlow |= enclosingBlock is JSLoopStatement;
                }

                State.Accesses.Add(
                    new FunctionAnalysis1stPass.Access(
                        GetParentNodeIndices(), StatementIndex, NodeIndex,
                        variable, isControlFlow
                        )
                    );
            }
            else
            {
                // Ignored because it is not an actual access
            }

            if (
                (ParentNode is JSPassByReferenceExpression) ||
                (
                    (ParentNode is JSReferenceExpression) &&
                    (Stack.Skip(2).FirstOrDefault() is JSPassByReferenceExpression)
                )
                )
            {
                State.VariablesPassedByRef.Add(variable.Name);
            }

            VisitChildren(variable);
        }
Ejemplo n.º 27
0
 public VariableEliminator(JSVariable variable, JSExpression replacement)
 {
     Variable    = variable;
     Replacement = replacement;
 }
        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);
        }
Ejemplo n.º 29
0
        protected bool IsEffectivelyConstant(JSVariable target, JSExpression source)
        {
            if ((source == null) || (source.IsNull))
            {
                return(false);
            }

            // Can't eliminate struct temporaries, since that might eliminate some implied copies.
            if (TypeUtil.IsStruct(target.Type))
            {
                return(false);
            }

            // Handle special cases where our interpretation of 'constant' needs to be more flexible
            {
                var ie = source as JSIndexerExpression;
                if (ie != null)
                {
                    if (
                        IsEffectivelyConstant(target, ie.Target) &&
                        IsEffectivelyConstant(target, ie.Index)
                        )
                    {
                        return(true);
                    }
                }
            }

            {
                var ae = source as JSArrayExpression;
                if (
                    (ae != null) &&
                    (from av in ae.Values select IsEffectivelyConstant(target, av)).All((b) => b)
                    )
                {
                    return(true);
                }
            }

            {
                var de = source as JSDotExpressionBase;
                if (
                    (de != null) &&
                    IsEffectivelyConstant(target, de.Target) &&
                    IsEffectivelyConstant(target, de.Member)
                    )
                {
                    return(true);
                }
            }

            {
                var ie = source as JSInvocationExpression;
                if (
                    (ie != null) && ie.ConstantIfArgumentsAre &&
                    IsEffectivelyConstant(target, ie.ThisReference) &&
                    ie.Arguments.All((a) => IsEffectivelyConstant(target, a))
                    )
                {
                    return(true);
                }

                if ((ie != null) && (ie.JSMethod != null))
                {
                    var sa = FunctionSource.GetSecondPass(ie.JSMethod);
                    if (sa != null)
                    {
                        if (sa.IsPure)
                        {
                            if (ie.Arguments.All((a) => IsEffectivelyConstant(target, a)))
                            {
                                return(true);
                            }
                            else
                            {
                                return(false);
                            }
                        }
                    }
                }
            }

            if ((source is JSUnaryOperatorExpression) || (source is JSBinaryOperatorExpression))
            {
                if (source.Children.OfType <JSExpression>().All((_v) => IsEffectivelyConstant(target, _v)))
                {
                    return(true);
                }
            }

            if (source.IsConstant)
            {
                return(true);
            }

            // Try to find a spot between the source variable's assignments where all of our
            //  copies and accesses can fit. If we find one, our variable is effectively constant.
            var v = source as JSVariable;

            if (v != null)
            {
                var assignments = (from a in FirstPass.Assignments where v.Equals(a.Target) select a).ToArray();
                if (assignments.Length < 1)
                {
                    return(v.IsParameter);
                }

                var targetAssignments = (from a in FirstPass.Assignments where v.Equals(a.Target) select a).ToArray();
                if (targetAssignments.Length < 1)
                {
                    return(false);
                }

                var targetAccesses = (from a in FirstPass.Accesses where target.Equals(a.Source) select a).ToArray();
                if (targetAccesses.Length < 1)
                {
                    return(false);
                }

                var targetFirstAssigned = targetAssignments.FirstOrDefault();
                var targetLastAssigned  = targetAssignments.LastOrDefault();

                var targetFirstAccessed = targetAccesses.FirstOrDefault();
                var targetLastAccessed  = targetAccesses.LastOrDefault();

                bool foundAssignmentSlot = false;

                for (int i = 0, c = assignments.Length; i < c; i++)
                {
                    int assignment = assignments[i].StatementIndex, nextAssignment = int.MaxValue;
                    if (i < c - 1)
                    {
                        nextAssignment = assignments[i + 1].StatementIndex;
                    }

                    if (
                        (targetFirstAssigned.StatementIndex >= assignment) &&
                        (targetFirstAssigned.StatementIndex < nextAssignment) &&
                        (targetFirstAccessed.StatementIndex >= assignment) &&
                        (targetLastAccessed.StatementIndex <= nextAssignment)
                        )
                    {
                        foundAssignmentSlot = true;
                        break;
                    }
                }

                if (!foundAssignmentSlot)
                {
                    return(false);
                }

                return(true);
            }

            return(false);
        }
Ejemplo n.º 30
0
        protected bool IsEffectivelyConstant(JSVariable target, JSExpression source)
        {
            if ((source == null) || (source.IsNull))
            {
                return(false);
            }

            // Can't eliminate struct temporaries, since that might eliminate some implied copies.
            if (TypeUtil.IsStruct(target.IdentifierType))
            {
                return(false);
            }

            // Handle special cases where our interpretation of 'constant' needs to be more flexible
            {
                var ie = source as JSIndexerExpression;
                if (ie != null)
                {
                    if (
                        IsEffectivelyConstant(target, ie.Target) &&
                        IsEffectivelyConstant(target, ie.Index)
                        )
                    {
                        return(true);
                    }
                }
            }

            {
                var ae = source as JSArrayExpression;
                if (
                    (ae != null) &&
                    (from av in ae.Values select IsEffectivelyConstant(target, av)).All((b) => b)
                    )
                {
                    return(true);
                }
            }

            {
                var de = source as JSDotExpressionBase;
                if (
                    (de != null) &&
                    IsEffectivelyConstant(target, de.Target) &&
                    IsEffectivelyConstant(target, de.Member)
                    )
                {
                    var pa = source as JSPropertyAccess;
                    if (pa != null)
                    {
                        // Property accesses must not be treated as constant since they call functions
                        // TODO: Use static analysis information to figure out whether the accessor is pure/has state dependencies
                        return(false);
                    }

                    return(true);
                }
            }

            {
                var ie = source as JSInvocationExpression;
                if (
                    (ie != null) && ie.ConstantIfArgumentsAre &&
                    IsEffectivelyConstant(target, ie.ThisReference) &&
                    ie.Arguments.All((a) => IsEffectivelyConstant(target, a))
                    )
                {
                    return(true);
                }

                if ((ie != null) && (ie.JSMethod != null))
                {
                    var sa = GetSecondPass(ie.JSMethod);
                    if (sa != null)
                    {
                        if (sa.IsPure)
                        {
                            if (ie.Arguments.All((a) => IsEffectivelyConstant(target, a)))
                            {
                                return(true);
                            }
                            else
                            {
                                return(false);
                            }
                        }
                    }
                }
            }

            if ((source is JSUnaryOperatorExpression) || (source is JSBinaryOperatorExpression))
            {
                if (source.Children.OfType <JSExpression>().All((_v) => IsEffectivelyConstant(target, _v)))
                {
                    return(true);
                }
            }

            if (source.IsConstant)
            {
                return(true);
            }

            // Try to find a spot between the source variable's assignments where all of our
            //  copies and accesses can fit. If we find one, our variable is effectively constant.
            // FIXME: I think this section might be fundamentally flawed. Do let me know if you agree. :)
            var v = source as JSVariable;

            if (v != null)
            {
                // Ensure that we never treat a local variable as constant if functions we call allow it to escape
                //  or modify it, because that can completely invalidate our purity analysis.
                if (VariablesExemptedFromEffectivelyConstantStatus.Contains(v.Identifier))
                {
                    return(false);
                }

                var sourceAssignments = (from a in FirstPass.Assignments where v.Identifier.Equals(a.Target) select a).ToArray();
                if (sourceAssignments.Length < 1)
                {
                    return(v.IsParameter);
                }

                var sourceAccesses = (from a in FirstPass.Accesses where v.Identifier.Equals(a.Source) select a).ToArray();
                if (sourceAccesses.Length < 1)
                {
                    return(false);
                }

                var targetAssignmentIndices = (from a in FirstPass.Assignments where target.Identifier.Equals(a.Target) select a.StatementIndex);
                var targetAccessIndices     = (from a in FirstPass.Accesses where target.Identifier.Equals(a.Source) select a.StatementIndex).ToArray();
                var targetUseIndices        = targetAccessIndices.Concat(targetAssignmentIndices).ToArray();

                if (sourceAssignments.Length == 1)
                {
                    if (targetAccessIndices.All((tai) => tai > sourceAssignments[0].StatementIndex))
                    {
                        return(true);
                    }
                }

                var sourceFirstAssigned = sourceAssignments.First();
                var sourceLastAssigned  = sourceAssignments.Last();

                var sourceFirstAccessed = sourceAccesses.First();
                var sourceLastAccessed  = sourceAccesses.Last();

                bool foundAssignmentSlot = false;

                for (int i = 0, c = targetUseIndices.Length; i < c; i++)
                {
                    int assignment = targetUseIndices[i], nextAssignment = int.MaxValue;
                    if (i < c - 1)
                    {
                        nextAssignment = targetUseIndices[i + 1];
                    }

                    if (
                        (sourceFirstAssigned.StatementIndex >= assignment) &&
                        (sourceLastAssigned.StatementIndex < nextAssignment) &&
                        (sourceFirstAccessed.StatementIndex >= assignment) &&
                        (sourceLastAccessed.StatementIndex <= nextAssignment)
                        )
                    {
                        if (TraceLevel >= 5)
                        {
                            Console.WriteLine("Found assignment slot for {0} <- {1} between {2} and {3}", target, source, assignment, nextAssignment);
                        }

                        foundAssignmentSlot = true;
                        break;
                    }
                }

                if (!foundAssignmentSlot)
                {
                    return(false);
                }

                return(true);
            }

            return(false);
        }