Exemplo n.º 1
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);
        }