public void VisitNode(JSFunctionExpression fn)
        {
            Function  = fn;
            FirstPass = GetFirstPass(Function.Method.QualifiedIdentifier);

            VisitChildren(fn);

            if (EnumeratorsToKill.Count > 0)
            {
                // Rerun the static analyzer since we made major changes
                InvalidateFirstPass();
                FirstPass = GetFirstPass(Function.Method.QualifiedIdentifier);

                // Scan to see if any of the enumerators we eliminated uses of are now
                //  unreferenced. If they are, eliminate them entirely.
                foreach (var variable in EnumeratorsToKill)
                {
                    var variableName = variable.Name;
                    var accesses     = (
                        from a in FirstPass.Accesses
                        where a.Source.Name == variableName
                        select a
                        );

                    if (!accesses.Any())
                    {
                        var eliminator = new VariableEliminator(
                            variable, new JSNullExpression()
                            );
                        eliminator.Visit(fn);
                    }
                }
            }
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            Function  = fn;
            FirstPass = GetFirstPass(Function.Method.QualifiedIdentifier);

            VisitChildren(fn);
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            Function  = fn;
            FirstPass = GetFirstPass(Function.Method.QualifiedIdentifier);

            VisitChildren(fn);

            if (ToDeclare.Count > 0)
            {
                int i = 0;

                foreach (var pd in ToDeclare)
                {
                    var es = new JSExpressionStatement(
                        new JSBinaryOperatorExpression(
                            JSOperator.Assignment, pd.Expression,
                            pd.DefaultValue ?? new JSDefaultValueLiteral(pd.Type),
                            pd.Type
                            ));

                    fn.Body.Statements.Insert(i++, es);
                }

                InvalidateFirstPass();
            }
        }
示例#4
0
        public FunctionAnalysis2ndPass(IFunctionSource functionSource, MethodInfo method)
        {
            FunctionSource = functionSource;
            Data           = null;
            _IsPure        = method.Metadata.HasAttribute("JSIL.Meta.JSIsPure");

            var parms = method.Metadata.GetAttributeParameters("JSIL.Meta.JSMutatedArguments");

            if (parms != null)
            {
                ModifiedVariables = new HashSet <string>();
                foreach (var p in parms)
                {
                    var s = p.Value as string;
                    if (s != null)
                    {
                        ModifiedVariables.Add(s);
                    }
                }
            }
            else if (!_IsPure)
            {
                ModifiedVariables = new HashSet <string>(from p in method.Parameters select p.Name);
            }
            else
            {
                ModifiedVariables = new HashSet <string>();
            }

            parms = method.Metadata.GetAttributeParameters("JSIL.Meta.JSEscapingArguments");
            if (parms != null)
            {
                EscapingVariables = new HashSet <string>();
                foreach (var p in parms)
                {
                    var s = p.Value as string;
                    if (s != null)
                    {
                        EscapingVariables.Add(s);
                    }
                }
            }
            else if (!_IsPure)
            {
                EscapingVariables = new HashSet <string>(from p in method.Parameters select p.Name);
            }
            else
            {
                EscapingVariables = new HashSet <string>();
            }

            VariableAliases = new Dictionary <string, HashSet <string> >();

            ResultVariable = null;
            ResultIsNew    = method.Metadata.HasAttribute("JSIL.Meta.JSResultIsNew");

            Trace(method.Member.FullName);
        }
示例#5
0
        public FunctionAnalysis1stPass FirstPass(QualifiedMemberIdentifier identifier, JSFunctionExpression function)
        {
            State = new FunctionAnalysis1stPass(identifier, function);

            Visit(function);

            State.Accesses.Sort(FunctionAnalysis1stPass.ItemComparer);
            State.Assignments.Sort(FunctionAnalysis1stPass.ItemComparer);

            var result = State;

            State = null;

            if (false)
            {
                var bg = new StaticAnalysis.BarrierGenerator(TypeSystem, function);
                bg.Generate();

                var targetFolder = Path.Combine(
                    Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Barriers"
                    );
                Directory.CreateDirectory(targetFolder);

                var typeName   = function.Method.QualifiedIdentifier.Type.ToString();
                var methodName = function.Method.Method.Name;

                if (typeName.Length >= 96)
                {
                    typeName = typeName.Substring(0, 93) + "…";
                }

                if (methodName.Length >= 32)
                {
                    methodName = methodName.Substring(0, 29) + "…";
                }

                var filename = String.Format("{0}.{1}", typeName, methodName);

                filename = filename.Replace("<", "").Replace(">", "").Replace("/", "");

                var targetFile = Path.Combine(
                    targetFolder,
                    String.Format("{0}.xml", filename)
                    );

                bg.SaveXML(targetFile);
            }

            return(result);
        }
示例#6
0
        public FunctionAnalysis1stPass FirstPass(QualifiedMemberIdentifier identifier, JSFunctionExpression function)
        {
            State = new FunctionAnalysis1stPass(identifier, function);

            Visit(function);

            State.Accesses.Sort(FunctionAnalysis1stPass.ItemComparer);
            State.Assignments.Sort(FunctionAnalysis1stPass.ItemComparer);

            var result = State;

            State = null;

            return(result);
        }
示例#7
0
        public FunctionAnalysis2ndPass(FunctionCache functionCache, MethodInfo method)
        {
            FunctionCache = functionCache;
            Data          = null;
            _IsPure       = method.Metadata.HasAttribute("JSIL.Meta.JSIsPure");

            var parms = method.Metadata.GetAttributeParameters("JSIL.Meta.JSMutatedArguments");

            if (parms != null)
            {
                ModifiedVariables = new HashSet <string>(GetAttributeArguments <string>(parms));
            }
            else if (!_IsPure)
            {
                ModifiedVariables = new HashSet <string>(from p in method.Parameters select p.Name);
            }
            else
            {
                ModifiedVariables = new HashSet <string>();
            }

            parms = method.Metadata.GetAttributeParameters("JSIL.Meta.JSEscapingArguments");
            if (parms != null)
            {
                EscapingVariables = new HashSet <string>(GetAttributeArguments <string>(parms));
            }
            else if (!_IsPure)
            {
                EscapingVariables = new HashSet <string>(from p in method.Parameters select p.Name);
            }
            else
            {
                EscapingVariables = new HashSet <string>();
            }

            VariableAliases = new Dictionary <string, HashSet <string> >();

            ResultVariable = null;
            ResultIsNew    = method.Metadata.HasAttribute("JSIL.Meta.JSResultIsNew");

            MutatedFields = null;

            Trace(method.Member.FullName);
        }
示例#8
0
        public void VisitNode(JSFunctionExpression fn)
        {
            // Create a new visitor for nested function expressions
            if (Stack.OfType <JSFunctionExpression>().Skip(1).FirstOrDefault() != null)
            {
                var nested = new OptimizeArrayEnumerators(TypeSystem, FunctionSource);
                nested.Visit(fn);

                return;
            }

            Function  = fn;
            FirstPass = FunctionSource.GetFirstPass(Function.Method.QualifiedIdentifier);

            VisitChildren(fn);

            if (EnumeratorsToKill.Count > 0)
            {
                // Rerun the static analyzer since we made major changes
                FunctionSource.InvalidateFirstPass(Function.Method.QualifiedIdentifier);
                FirstPass = FunctionSource.GetFirstPass(Function.Method.QualifiedIdentifier);

                // Scan to see if any of the enumerators we eliminated uses of are now
                //  unreferenced. If they are, eliminate them entirely.
                foreach (var variable in EnumeratorsToKill)
                {
                    var variableName = variable.Name;
                    var accesses     = (
                        from a in FirstPass.Accesses
                        where a.Source.Name == variableName
                        select a
                        );

                    if (!accesses.Any())
                    {
                        var eliminator = new VariableEliminator(
                            variable, new JSNullExpression()
                            );
                        eliminator.Visit(fn);
                    }
                }
            }
        }
示例#9
0
        public void VisitNode(JSFunctionExpression fn)
        {
            // Create a new visitor for nested function expressions
            if (Stack.OfType <JSFunctionExpression>().Skip(1).FirstOrDefault() != null)
            {
                bool eliminated = false;

                do
                {
                    var nested = new EliminateSingleUseTemporaries(TypeSystem, fn.AllVariables, FunctionSource);
                    nested.Visit(fn);
                    eliminated = nested.EliminatedVariables.Count > 0;
                } while (eliminated);

                return;
            }

            var nullList = new List <int>();

            FirstPass = FunctionSource.GetFirstPass(fn.Method.QualifiedIdentifier);
            if (FirstPass == null)
            {
                throw new InvalidOperationException(String.Format(
                                                        "No first pass static analysis data for method '{0}'",
                                                        fn.Method.QualifiedIdentifier
                                                        ));
            }

            VisitChildren(fn);

            foreach (var v in fn.AllVariables.Values.ToArray())
            {
                if (v.IsThis || v.IsParameter)
                {
                    continue;
                }

                var valueType = v.GetActualType(TypeSystem);
                if (TypeUtil.IsIgnoredType(valueType))
                {
                    continue;
                }

                var assignments = (from a in FirstPass.Assignments where v.Equals(a.Target) select a).ToArray();
                var accesses    = (from a in FirstPass.Accesses where v.Equals(a.Source) select a).ToArray();
                var invocations = (from i in FirstPass.Invocations where v.Name == i.ThisVariable select i).ToArray();

                if (FirstPass.VariablesPassedByRef.Contains(v.Name))
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is passed by reference.", v));
                    }

                    continue;
                }

                if (assignments.FirstOrDefault() == null)
                {
                    if (accesses.Length == 0)
                    {
                        if (TraceLevel >= 1)
                        {
                            Debug.WriteLine(String.Format("Eliminating {0} because it is never used.", v));
                        }

                        EliminatedVariables.Add(v);
                        EliminateVariable(fn, v, new JSEliminatedVariable(v), fn.Method.QualifiedIdentifier);
                    }
                    else
                    {
                        if (TraceLevel >= 2)
                        {
                            Debug.WriteLine(String.Format("Never found an initial assignment for {0}.", v));
                        }
                    }

                    continue;
                }

                if (invocations.Length > 0)
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; methods are invoked on it.", v));
                    }

                    continue;
                }

                if ((from a in accesses where a.IsControlFlow select a).FirstOrDefault() != null)
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it participates in control flow.", v));
                    }

                    continue;
                }

                if (assignments.Length > 1)
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is reassigned.", v));
                    }

                    continue;
                }

                var copies = (from a in FirstPass.Assignments where v.Equals(a.SourceVariable) select a).ToArray();
                if ((copies.Length + accesses.Length) > 1)
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is used multiple times.", v));
                    }

                    continue;
                }

                var replacement = assignments.First().NewValue;
                if (replacement.SelfAndChildrenRecursive.Contains(v))
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it contains a self-reference.", v));
                    }

                    continue;
                }

                if (!IsEffectivelyConstant(v, replacement))
                {
                    if (TraceLevel >= 2)
                    {
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it is not a constant expression.", v));
                    }

                    continue;
                }

                if (TraceLevel >= 1)
                {
                    Debug.WriteLine(String.Format("Eliminating {0} <- {1}", v, replacement));
                }

                var transferDataTo = replacement as JSVariable;
                if (transferDataTo != null)
                {
                    foreach (var access in accesses)
                    {
                        FirstPass.Accesses.Remove(access);
                        FirstPass.Accesses.Add(new FunctionAnalysis1stPass.Access(
                                                   access.ParentNodeIndices, access.StatementIndex, access.NodeIndex,
                                                   transferDataTo, access.IsControlFlow
                                                   ));
                    }

                    foreach (var assignment in assignments)
                    {
                        FirstPass.Assignments.Remove(assignment);
                        FirstPass.Assignments.Add(new FunctionAnalysis1stPass.Assignment(
                                                      assignment.ParentNodeIndices, assignment.StatementIndex, assignment.NodeIndex,
                                                      transferDataTo, assignment.NewValue, assignment.Operator,
                                                      assignment.TargetType, assignment.SourceType
                                                      ));
                    }

                    foreach (var invocation in invocations)
                    {
                        FirstPass.Invocations.Remove(invocation);
                        FirstPass.Invocations.Add(new FunctionAnalysis1stPass.Invocation(
                                                      invocation.ParentNodeIndices, invocation.StatementIndex, invocation.NodeIndex,
                                                      transferDataTo, invocation.Method, invocation.Variables
                                                      ));
                    }
                }

                FirstPass.Assignments.RemoveAll((a) => v.Equals(a.Target));
                FirstPass.Accesses.RemoveAll((a) => v.Equals(a.Source));

                EliminatedVariables.Add(v);

                EliminateVariable(fn, v, replacement, fn.Method.QualifiedIdentifier);
            }
        }
示例#10
0
        public void VisitNode(JSFunctionExpression fn)
        {
            FirstPass = GetFirstPass(fn.Method.QualifiedIdentifier);
            if (FirstPass == null)
            {
                throw new InvalidOperationException(String.Format(
                                                        "No first pass static analysis data for method '{0}'",
                                                        fn.Method.QualifiedIdentifier
                                                        ));
            }

            ExemptVariablesFromEffectivelyConstantStatus();

            foreach (var v in fn.AllVariables.Values.ToArray())
            {
                if (v.IsThis || v.IsParameter)
                {
                    continue;
                }

                var assignments         = (from a in FirstPass.Assignments where v.Identifier.Equals(a.Target) select a).ToArray();
                var reassignments       = (from a in FirstPass.Assignments where v.Identifier.Equals(a.SourceVariable) select a).ToArray();
                var accesses            = (from a in FirstPass.Accesses where v.Identifier.Equals(a.Source) select a).ToArray();
                var invocations         = (from i in FirstPass.Invocations where v.Name == i.ThisVariable select i).ToArray();
                var unsafeInvocations   = FilterInvocations(invocations);
                var isPassedByReference = FirstPass.VariablesPassedByRef.Contains(v.Name);

                if (assignments.FirstOrDefault() == null)
                {
                    if ((accesses.Length == 0) && (invocations.Length == 0) && (reassignments.Length == 0) && !isPassedByReference)
                    {
                        if (TraceLevel >= 1)
                        {
                            Console.WriteLine("Eliminating {0} because it is never used.", v);
                        }

                        if (!DryRun)
                        {
                            EliminatedVariables.Add(v);
                            EliminateVariable(fn, v, new JSEliminatedVariable(v), fn.Method.QualifiedIdentifier);

                            // We've invalidated the static analysis data so the best choice is to abort.
                            break;
                        }
                    }
                    else
                    {
                        if (TraceLevel >= 2)
                        {
                            Console.WriteLine("Never found an initial assignment for {0}.", v);
                        }
                    }

                    continue;
                }

                var valueType = v.GetActualType(TypeSystem);
                if (TypeUtil.IsIgnoredType(valueType))
                {
                    continue;
                }

                if (FirstPass.VariablesPassedByRef.Contains(v.Name))
                {
                    if (TraceLevel >= 2)
                    {
                        Console.WriteLine("Cannot eliminate {0}; it is passed by reference.", v);
                    }

                    continue;
                }

                if (unsafeInvocations.Length > 1)
                {
                    if (TraceLevel >= 2)
                    {
                        Console.WriteLine("Cannot eliminate {0}; methods are invoked on it multiple times that are not provably safe.", v);
                    }

                    continue;
                }

                if ((from a in accesses where a.IsControlFlow select a).FirstOrDefault() != null)
                {
                    if (TraceLevel >= 2)
                    {
                        Console.WriteLine("Cannot eliminate {0}; it participates in control flow.", v);
                    }

                    continue;
                }

                if (assignments.Length > 1)
                {
                    if (TraceLevel >= 2)
                    {
                        Console.WriteLine("Cannot eliminate {0}; it is reassigned.", v);
                    }

                    continue;
                }

                var replacementAssignment = assignments.First();
                var replacement           = replacementAssignment.NewValue;
                if (replacement.SelfAndChildrenRecursive.Contains(v))
                {
                    if (TraceLevel >= 2)
                    {
                        Console.WriteLine("Cannot eliminate {0}; it contains a self-reference.", v);
                    }

                    continue;
                }

                var copies = (from a in FirstPass.Assignments where v.Identifier.Equals(a.SourceVariable) select a).ToArray();
                if (
                    (copies.Length + accesses.Length) > 1
                    )
                {
                    if (replacement is JSLiteral)
                    {
                        if (TraceLevel >= 5)
                        {
                            Console.WriteLine("Skipping veto of elimination for {0} because it is a literal.", v);
                        }
                    }
                    else
                    {
                        if (TraceLevel >= 2)
                        {
                            Console.WriteLine("Cannot eliminate {0}; it is used multiple times.", v);
                        }

                        continue;
                    }
                }

                if (!IsEffectivelyConstant(v, replacement))
                {
                    if (TraceLevel >= 2)
                    {
                        Console.WriteLine("Cannot eliminate {0}; {1} is not a constant expression.", v, replacement);
                    }

                    continue;
                }

                var replacementField = JSPointerExpressionUtil.UnwrapExpression(replacement) as JSFieldAccess;
                if (replacementField == null)
                {
                    var replacementRef = replacement as JSReferenceExpression;
                    if (replacementRef != null)
                    {
                        replacementField = replacementRef.Referent as JSFieldAccess;
                    }
                }

                var _affectedFields = replacement.SelfAndChildrenRecursive.OfType <JSField>();
                if (replacementField != null)
                {
                    _affectedFields = _affectedFields.Concat(new[] { replacementField.Field });
                }

                var affectedFields = new HashSet <FieldInfo>((from jsf in _affectedFields select jsf.Field));
                _affectedFields = null;

                if ((affectedFields.Count > 0) || (replacementField != null))
                {
                    var firstAssignment = assignments.FirstOrDefault();
                    var lastAccess      = accesses.LastOrDefault();

                    bool invalidatedByLaterFieldAccess = false;

                    foreach (var fieldAccess in FirstPass.FieldAccesses)
                    {
                        // Note that we only compare the FieldInfo, not the this-reference.
                        // Otherwise, aliasing (accessing the same field through two this references) would cause us
                        //  to incorrectly eliminate a local.
                        if (!affectedFields.Contains(fieldAccess.Field.Field))
                        {
                            continue;
                        }

                        // Ignore field accesses before the replacement was initialized
                        if (fieldAccess.NodeIndex <= replacementAssignment.NodeIndex)
                        {
                            continue;
                        }

                        // If the field access comes after the last use of the temporary, we don't care
                        if ((lastAccess != null) && (fieldAccess.StatementIndex > lastAccess.StatementIndex))
                        {
                            continue;
                        }

                        // It's a read, so no impact on whether this optimization is valid
                        if (fieldAccess.IsRead)
                        {
                            continue;
                        }

                        if (TraceLevel >= 2)
                        {
                            Console.WriteLine(String.Format("Cannot eliminate {0}; {1} is potentially mutated later", v, fieldAccess.Field.Field));
                        }

                        invalidatedByLaterFieldAccess = true;
                        break;
                    }

                    if (invalidatedByLaterFieldAccess)
                    {
                        continue;
                    }

                    foreach (var invocation in FirstPass.Invocations)
                    {
                        // If the invocation comes after (or is) the last use of the temporary, we don't care
                        if ((lastAccess != null) && (invocation.StatementIndex >= lastAccess.StatementIndex))
                        {
                            continue;
                        }

                        // Same goes for the first assignment.
                        if ((firstAssignment != null) && (invocation.StatementIndex <= firstAssignment.StatementIndex))
                        {
                            continue;
                        }

                        var invocationSecondPass = GetSecondPass(invocation.Method);
                        if (
                            (invocationSecondPass == null) ||
                            (invocationSecondPass.MutatedFields == null)
                            )
                        {
                            if (invocation.ThisAndVariables.Any((kvp) => kvp.Value.ToEnumerable().Contains(v.Identifier)))
                            {
                                if (TraceLevel >= 2)
                                {
                                    Console.WriteLine(String.Format("Cannot eliminate {0}; a method call without field mutation data ({1}) is invoked between its initialization and use with it as an argument", v, invocation.Method ?? invocation.NonJSMethod));
                                }

                                invalidatedByLaterFieldAccess = true;
                            }
                        }
                        else if (affectedFields.Any(invocationSecondPass.FieldIsMutatedRecursively))
                        {
                            if (TraceLevel >= 2)
                            {
                                Console.WriteLine(String.Format("Cannot eliminate {0}; a method call ({1}) potentially mutates a field it references", v, invocation.Method ?? invocation.NonJSMethod));
                            }

                            invalidatedByLaterFieldAccess = true;
                        }
                    }

                    if (invalidatedByLaterFieldAccess)
                    {
                        continue;
                    }
                }

                if (TraceLevel >= 1)
                {
                    Console.WriteLine(String.Format("Eliminating {0} <- {1}", v, replacement));
                }

                if (!DryRun)
                {
                    EliminatedVariables.Add(v);
                    EliminateVariable(fn, v, replacement, fn.Method.QualifiedIdentifier);

                    // We've invalidated the static analysis data so the best choice is to abort.
                    break;
                }
            }
        }
示例#11
0
        public FunctionAnalysis2ndPass(FunctionCache functionCache, FunctionAnalysis1stPass data)
        {
            FunctionAnalysis2ndPass invocationSecondPass;

            FunctionCache = functionCache;
            Data          = data;

            if (data.Function.Method.Method.Metadata.HasAttribute("JSIsPure"))
            {
                _IsPure = true;
            }
            else
            {
                _IsPure = (data.StaticReferences.Count == 0) &&
                          (data.SideEffects.Count == 0);
            }

            VariableAliases = new Dictionary <string, HashSet <string> >();
            foreach (var assignment in data.Assignments)
            {
                if (assignment.SourceVariable != null)
                {
                    HashSet <string> aliases;
                    if (!VariableAliases.TryGetValue(assignment.SourceVariable.Identifier, out aliases))
                    {
                        VariableAliases[assignment.SourceVariable.Identifier] = aliases = new HashSet <string>();
                    }

                    aliases.Add(assignment.Target.Identifier);
                }
            }

            var parameterNames = new HashSet <string>(
                from p in data.Function.Parameters select p.Name
                );

            var parms = data.Function.Method.Method.Metadata.GetAttributeParameters("JSIL.Meta.JSMutatedArguments");

            if (parms != null)
            {
                ModifiedVariables = new HashSet <string>();
                foreach (var p in parms)
                {
                    var s = p.Value as string;
                    if (s != null)
                    {
                        ModifiedVariables.Add(s);
                    }
                }
            }
            else
            {
                ModifiedVariables = new HashSet <string>(
                    data.ModificationCount.Where((kvp) => {
                    var isParameter = parameterNames.Contains(kvp.Key);
                    return(kvp.Value >= (isParameter ? 1 : 2));
                }).Select((kvp) => kvp.Key)
                    );

                if (TraceModifications && (ModifiedVariables.Count > 0))
                {
                    Console.WriteLine("Tagged variables as modified due to modification count: {0}", String.Join(", ", ModifiedVariables));
                }

                foreach (var v in Data.VariablesPassedByRef)
                {
                    if (TraceModifications)
                    {
                        Console.WriteLine("Tagging variable '{0}' as modified because it is passed byref", v);
                    }

                    ModifiedVariables.Add(v);
                }
            }

            parms = data.Function.Method.Method.Metadata.GetAttributeParameters("JSIL.Meta.JSEscapingArguments");
            if (parms != null)
            {
                EscapingVariables = new HashSet <string>();
                foreach (var p in parms)
                {
                    var s = p.Value as string;
                    if (s != null)
                    {
                        EscapingVariables.Add(s);
                    }
                }
            }
            else
            {
                EscapingVariables = Data.EscapingVariables;

                // Scan over all the invocations performed by this function and see if any of them cause
                //  a variable to escape
                foreach (var invocation in Data.Invocations)
                {
                    if (invocation.Method != null)
                    {
                        invocationSecondPass = functionCache.GetSecondPass(invocation.Method, Data.Identifier);
                    }
                    else
                    {
                        invocationSecondPass = null;
                    }

                    foreach (var invocationKvp in invocation.Variables)
                    {
                        if (invocationKvp.Value.Length == 0)
                        {
                            continue;
                        }

                        bool escapes;

                        if (invocationSecondPass != null)
                        {
                            escapes = invocationSecondPass.EscapingVariables.Contains(invocationKvp.Key);
                        }
                        else
                        {
                            escapes = true;
                        }

                        if (escapes)
                        {
                            if (invocationKvp.Value.Length > 1)
                            {
                                // FIXME: Is this right?
                                // Multiple variables -> a binary operator expression or an invocation.
                                // In either case, it should be impossible for any of them to escape without being flagged otherwise.

                                if (TraceEscapes)
                                {
                                    Console.WriteLine(
                                        "Parameter '{0}::{1}' escapes but it is a composite so we are not flagging variables {2}",
                                        GetMethodName(invocation.Method), invocationKvp.Key, String.Join(", ", invocationKvp.Value)
                                        );
                                }

                                continue;
                            }
                            else
                            {
                                var escapingVariable = invocationKvp.Value[0];

                                if (TraceEscapes)
                                {
                                    Console.WriteLine("Parameter '{0}::{1}' escapes; flagging variable '{2}'", GetMethodName(invocation.Method), invocationKvp.Key, escapingVariable);
                                }

                                Data.EscapingVariables.Add(escapingVariable);
                            }
                        }
                    }
                }
            }

            ResultVariable = Data.ResultVariable;
            ResultIsNew    = Data.ResultIsNew;

            var seenMethods = new HashSet <string>();
            var rm          = Data.ResultMethod;

            while (rm != null)
            {
                var currentMethod = rm.QualifiedIdentifier.ToString();
                if (seenMethods.Contains(currentMethod))
                {
                    break;
                }

                seenMethods.Add(currentMethod);

                var rmfp = functionCache.GetFirstPass(rm.QualifiedIdentifier, data.Identifier);
                if (rmfp == null)
                {
                    ResultIsNew = rm.Method.Metadata.HasAttribute("JSIL.Meta.JSResultIsNew");
                    break;
                }

                rm          = rmfp.ResultMethod;
                ResultIsNew = rmfp.ResultIsNew;
            }

            if (
                !data.Function.Method.Method.IsStatic &&
                data.Function.Method.Method.DeclaringType.IsImmutable &&
                data.ReassignsThisReference
                )
            {
                ViolatesThisReferenceImmutability = true;
            }

            MutatedFields = new HashSet <FieldInfo>(
                from fa in data.FieldAccesses where !fa.IsRead select fa.Field.Field
                );

            var recursivelyMutatedFields = new HashSet <HashSet <FieldInfo> >();

            foreach (var invocation in Data.Invocations)
            {
                if (invocation.Method != null)
                {
                    invocationSecondPass = functionCache.GetSecondPass(invocation.Method, Data.Identifier);
                }
                else
                {
                    invocationSecondPass = null;
                }

                if ((invocationSecondPass == null) || (invocationSecondPass.MutatedFields == null))
                {
                    // Can't know for sure.
                    MutatedFields = null;
                    break;
                }

                recursivelyMutatedFields.Add(invocationSecondPass.MutatedFields);

                foreach (var rrmf in invocationSecondPass.RecursivelyMutatedFields)
                {
                    recursivelyMutatedFields.Add(rrmf);
                }
            }

            RecursivelyMutatedFields = recursivelyMutatedFields.ToArray();

            Trace(data.Function.Method.Reference.FullName);
        }
示例#12
0
        public FunctionAnalysis2ndPass(IFunctionSource functionSource, FunctionAnalysis1stPass data)
        {
            FunctionSource = functionSource;
            Data           = data;

            if (data.Function.Method.Method.Metadata.HasAttribute("JSIsPure"))
            {
                _IsPure = true;
            }
            else
            {
                _IsPure = (data.StaticReferences.Count == 0) &&
                          (data.SideEffects.Count == 0);
            }

            VariableAliases = new Dictionary <string, HashSet <string> >();
            foreach (var assignment in data.Assignments)
            {
                if (assignment.SourceVariable != null)
                {
                    HashSet <string> aliases;
                    if (!VariableAliases.TryGetValue(assignment.SourceVariable.Identifier, out aliases))
                    {
                        VariableAliases[assignment.SourceVariable.Identifier] = aliases = new HashSet <string>();
                    }

                    aliases.Add(assignment.Target.Identifier);
                }
            }

            var parameterNames = new HashSet <string>(
                from p in data.Function.Parameters select p.Name
                );

            var parms = data.Function.Method.Method.Metadata.GetAttributeParameters("JSIL.Meta.JSMutatedArguments");

            if (parms != null)
            {
                ModifiedVariables = new HashSet <string>();
                foreach (var p in parms)
                {
                    var s = p.Value as string;
                    if (s != null)
                    {
                        ModifiedVariables.Add(s);
                    }
                }
            }
            else
            {
                ModifiedVariables = new HashSet <string>(
                    data.ModificationCount.Where((kvp) => {
                    var isParameter = parameterNames.Contains(kvp.Key);
                    return(kvp.Value >= (isParameter ? 1 : 2));
                }).Select((kvp) => kvp.Key)
                    );

                foreach (var v in Data.VariablesPassedByRef)
                {
                    ModifiedVariables.Add(v);
                }
            }

            parms = data.Function.Method.Method.Metadata.GetAttributeParameters("JSIL.Meta.JSEscapingArguments");
            if (parms != null)
            {
                EscapingVariables = new HashSet <string>();
                foreach (var p in parms)
                {
                    var s = p.Value as string;
                    if (s != null)
                    {
                        EscapingVariables.Add(s);
                    }
                }
            }
            else
            {
                EscapingVariables = Data.EscapingVariables;

                // Scan over all the invocations performed by this function and see if any of them cause
                //  a variable to escape
                FunctionAnalysis2ndPass invocationSecondPass;
                foreach (var invocation in Data.Invocations)
                {
                    if (invocation.Method != null)
                    {
                        invocationSecondPass = functionSource.GetSecondPass(invocation.Method);
                    }
                    else
                    {
                        invocationSecondPass = null;
                    }

                    foreach (var invocationKvp in invocation.Variables)
                    {
                        bool escapes;

                        if (invocationSecondPass != null)
                        {
                            escapes = invocationSecondPass.EscapingVariables.Contains(invocationKvp.Key);
                        }
                        else
                        {
                            escapes = true;
                        }

                        if (escapes)
                        {
                            foreach (var variableName in invocationKvp.Value)
                            {
                                Data.EscapingVariables.Add(variableName);
                            }
                        }
                    }
                }
            }

            ResultVariable = Data.ResultVariable;
            ResultIsNew    = Data.ResultIsNew;

            var seenMethods = new HashSet <string>();
            var rm          = Data.ResultMethod;

            while (rm != null)
            {
                var currentMethod = rm.QualifiedIdentifier.ToString();
                if (seenMethods.Contains(currentMethod))
                {
                    break;
                }

                seenMethods.Add(currentMethod);

                var rmfp = functionSource.GetFirstPass(rm.QualifiedIdentifier);
                if (rmfp == null)
                {
                    ResultIsNew = rm.Method.Metadata.HasAttribute("JSIL.Meta.JSResultIsNew");
                    break;
                }

                rm          = rmfp.ResultMethod;
                ResultIsNew = rmfp.ResultIsNew;
            }

            Trace(data.Function.Method.Reference.FullName);
        }
示例#13
0
        public FunctionAnalysis2ndPass(IFunctionSource functionSource, FunctionAnalysis1stPass data)
        {
            FunctionSource = functionSource;
            Data           = data;
            _IsPure        = (data.StaticReferences.Count == 0) &&
                             (data.SideEffects.Count == 0);

            VariableAliases = new Dictionary <string, HashSet <string> >();
            foreach (var assignment in data.Assignments)
            {
                if (assignment.SourceVariable != null)
                {
                    HashSet <string> aliases;
                    if (!VariableAliases.TryGetValue(assignment.SourceVariable.Identifier, out aliases))
                    {
                        VariableAliases[assignment.SourceVariable.Identifier] = aliases = new HashSet <string>();
                    }

                    aliases.Add(assignment.Target.Identifier);
                }
            }

            var parameterNames = new HashSet <string>(
                from p in data.Function.Parameters select p.Name
                );

            ModifiedVariables = new HashSet <string>(
                data.ModificationCount.Where((kvp) => {
                var isParameter = parameterNames.Contains(kvp.Key);
                return(kvp.Value >= (isParameter ? 1 : 2));
            }).Select((kvp) => kvp.Key)
                );

            foreach (var v in Data.VariablesPassedByRef)
            {
                ModifiedVariables.Add(v);
            }

            EscapingVariables = Data.EscapingVariables;
            ResultVariable    = Data.ResultVariable;
            ResultIsNew       = Data.ResultIsNew;

            var seenMethods = new HashSet <string>();
            var rm          = Data.ResultMethod;

            while (rm != null)
            {
                var currentMethod = rm.QualifiedIdentifier.ToString();
                if (seenMethods.Contains(currentMethod))
                {
                    break;
                }

                seenMethods.Add(currentMethod);

                var rmfp = functionSource.GetFirstPass(rm.QualifiedIdentifier);
                if (rmfp == null)
                {
                    ResultIsNew = rm.Method.Metadata.HasAttribute("JSIL.Meta.JSResultIsNew");
                    break;
                }

                rm          = rmfp.ResultMethod;
                ResultIsNew = rmfp.ResultIsNew;
            }

            Trace(data.Function.Method.Reference.FullName);
        }