protected bool IsEffectivelyConstant(JSExpression expression)
        {
            if (expression.IsConstant)
            {
                return(true);
            }

            var invocation = expression as JSInvocationExpression;
            FunctionAnalysis2ndPass secondPass = null;

            if ((invocation != null) && (invocation.JSMethod != null))
            {
                secondPass = FunctionSource.GetSecondPass(invocation.JSMethod);

                if ((secondPass != null) && secondPass.IsPure)
                {
                    return(true);
                }

                var methodName = invocation.JSMethod.Method.Name;
                if ((methodName == "IDisposable.Dispose") || (methodName == "Dispose"))
                {
                    var thisType = invocation.ThisReference.GetActualType(TypeSystem);

                    if (thisType != null)
                    {
                        var typeInfo = TypeInfo.GetExisting(thisType);

                        if ((typeInfo != null) && typeInfo.Metadata.HasAttribute("JSIL.Meta.JSPureDispose"))
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Пример #2
0
        protected bool DetermineIfPure()
        {
            foreach (var i in Data.Invocations)
            {
                if (i.Method == null)
                {
                    return(false);
                }

                var secondPass = FunctionSource.GetSecondPass(i.Method);
                if (secondPass == null)
                {
                    return(false);
                }

                if (!secondPass.IsPure)
                {
                    return(false);
                }
            }

            return(_IsPure);
        }
Пример #3
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);
        }
Пример #4
0
        protected bool IsCopyNeeded(JSExpression value)
        {
            if ((value == null) || (value.IsNull))
            {
                return(false);
            }

            while (value is JSReferenceExpression)
            {
                value = ((JSReferenceExpression)value).Referent;
            }

            var valueType = value.GetActualType(TypeSystem);

            if (!TypeUtil.IsStruct(valueType))
            {
                return(false);
            }

            if (valueType.FullName.StartsWith("System.Nullable"))
            {
                return(false);
            }

            if (
                (value is JSLiteral) ||
                (value is JSNewExpression) ||
                (value is JSPassByReferenceExpression)
                )
            {
                return(false);
            }

            if (IsImmutable(value))
            {
                return(false);
            }

            // If the expression is a parameter that is only used once and isn't aliased,
            //  we don't need to copy it.
            var rightVar = value as JSVariable;

            if (rightVar != null)
            {
                int referenceCount;
                if (
                    ReferenceCounts.TryGetValue(rightVar.Identifier, out referenceCount) &&
                    (referenceCount == 1) && !rightVar.IsReference && rightVar.IsParameter &&
                    !SecondPass.VariableAliases.ContainsKey(rightVar.Identifier)
                    )
                {
                    if (Tracing)
                    {
                        Debug.WriteLine(String.Format("Returning false from IsCopyNeeded for parameter {0} because reference count is 1 and it has no aliases", value));
                    }

                    return(false);
                }
            }

            var rightInvocation = value as JSInvocationExpression;

            if (rightInvocation == null)
            {
                return(true);
            }

            var invokeMethod = rightInvocation.JSMethod;

            if (invokeMethod == null)
            {
                return(true);
            }

            var secondPass = FunctionSource.GetSecondPass(invokeMethod);

            if (secondPass == null)
            {
                return(true);
            }

            // If this expression is the return value of a function invocation, we can eliminate struct
            //  copies if the return value is a 'new' expression.
            if (secondPass.ResultIsNew)
            {
                return(false);
            }

            // We can also eliminate a return value copy if the return value is one of the function's
            //  arguments, and we are sure that argument does not need a copy either.
            if (secondPass.ResultVariable != null)
            {
                var parameters     = invokeMethod.Method.Parameters;
                int parameterIndex = -1;

                for (var i = 0; i < parameters.Length; i++)
                {
                    if (parameters[i].Name != secondPass.ResultVariable)
                    {
                        continue;
                    }

                    parameterIndex = i;
                    break;
                }

                if (parameterIndex < 0)
                {
                    return(true);
                }

                return(IsCopyNeeded(rightInvocation.Arguments[parameterIndex]));
            }

            return(true);
        }
Пример #5
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);
        }
Пример #6
0
 protected FunctionAnalysis2ndPass GetSecondPass(JSMethod method)
 {
     return(FunctionSource.GetSecondPass(method, Member));
 }