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);

            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();
            }
        }
        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);
                    }
                }
            }
        }
Example #4
0
        public static JSTemporaryVariable ForFunction(
            JSFunctionExpression function, TypeReference type,
            IFunctionSource functionSource
            )
        {
            var index = function.TemporaryVariableTypes.Count;

            function.TemporaryVariableTypes.Add(type);

            MethodReference methodRef = null;

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

            var id     = string.Format("$temp{0:X2}", index);
            var result = new JSTemporaryVariable(id, type, methodRef);

            function.AllVariables.Add(id, result);

            // HACK: If the static analysis data for the function is stale, this temporary
            //  variable might get eliminated later despite being in use.
            // We should really just fix all the transforms that aren't invalidating static
            //  analysis data when they should, but this is good enough for now.
            if (function.Method != null)
            {
                functionSource.InvalidateFirstPass(function.Method.QualifiedIdentifier);
            }

            return(result);
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            // Create a new visitor for nested function expressions
            if (Stack.OfType <JSFunctionExpression>().Skip(1).FirstOrDefault() != null)
            {
                new IntroduceVariableReferences(JSIL, fn.AllVariables, new HashSet <string>(from p in fn.Parameters select p.Name)).Visit(fn);
                return;
            }

            VisitChildren(fn);

            foreach (var r in ReferencesToTransform)
            {
                var cr = GetConstructedReference(r);

                if (cr == null)
                {
                    // We have already done the variable transform for this variable in the past.
                    continue;
                }

                // For 'ref this', we need to replace each individual expression, because we can't
                //  rename the this-variable.
                if (cr.IsThis)
                {
                    var refThis = JSIL.NewReference(Variables["this"]);
                    fn.ReplaceChildRecursive(r, refThis);
                    continue;
                }

                var parameter = (from p in fn.Parameters
                                 where p.Identifier == cr.Identifier
                                 select p).FirstOrDefault();

                if (parameter != null)
                {
                    TransformParameterIntoReference(parameter, fn.Body);
                }
                else
                {
                    var declaration = (from kvp in Declarations
                                       let vds = kvp.Key
                                                 from ivd in vds.Declarations.Select((vd, i) => new { vd = vd, i = i })
                                                 where MatchesConstructedReference(ivd.vd.Left, cr)
                                                 select new { vds = vds, vd = ivd.vd, i = ivd.i, block = kvp.Value }).FirstOrDefault();

                    if (declaration == null)
                    {
                        throw new InvalidOperationException(String.Format("Could not locate declaration for {0}", cr));
                    }

                    TransformVariableIntoReference(
                        (JSVariable)declaration.vd.Left,
                        declaration.vds,
                        declaration.i,
                        declaration.block
                        );
                }
            }
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            Function  = fn;
            FirstPass = GetFirstPass(Function.Method.QualifiedIdentifier);

            VisitChildren(fn);
        }
Example #7
0
        internal JSFunctionExpression Create(
            MethodInfo info, MethodDefinition methodDef, MethodReference method,
            QualifiedMemberIdentifier identifier, ILBlockTranslator translator,
            IEnumerable <JSVariable> parameters, JSBlockStatement body
            )
        {
            return(Cache.GetOrCreate(identifier, () => {
                var result = new JSFunctionExpression(
                    new JSMethod(method, info, MethodTypes),
                    translator.Variables,
                    parameters,
                    body,
                    MethodTypes
                    );

                OptimizationQueue.TryEnqueue(identifier);

                return new Entry {
                    Identifier = identifier,
                    Info = info,
                    Reference = method,
                    Expression = result,
                    Variables = translator.Variables,
                    ParameterNames = translator.ParameterNames,
                    SpecialIdentifiers = translator.SpecialIdentifiers
                };
            }).Expression);
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            Function = fn;
            FirstPass = GetFirstPass(Function.Method.QualifiedIdentifier);

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

            VisitChildren(fn);

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

                var vds = new JSVariableDeclarationStatement();

                foreach (var pd in ToDeclare) {
                    vds.Declarations.Add(
                        new JSBinaryOperatorExpression(
                            JSOperator.Assignment, pd.Expression,
                            pd.DefaultValue ?? new JSDefaultValueLiteral(pd.Type),
                            pd.Type
                        )
                    );
                }

                fn.Body.Statements.Insert(i++, vds);

                InvalidateFirstPass();
            }
        }
Example #10
0
        /// <summary>
        /// Writes a method signature to the output.
        /// </summary>
        public void WriteSignatureToOutput(
            JavascriptFormatter output, JSFunctionExpression enclosingFunction,
            MethodReference methodReference, MethodSignature methodSignature,
            TypeReferenceContext referenceContext,
            bool forConstructor
            )
        {
            int index;
            var record = new CachedSignatureRecord(methodReference, methodSignature, forConstructor);

            if ((enclosingFunction.Method != null) && (enclosingFunction.Method.Method != null))
            {
                var      functionIdentifier = enclosingFunction.Method.Method.Identifier;
                CacheSet localSignatureSet;

                if (LocalCachedSets.TryGetValue(functionIdentifier, out localSignatureSet))
                {
                    if (localSignatureSet.Signatures.TryGetValue(record, out index))
                    {
                        output.WriteRaw("$s{0:X2}", index);

                        return;
                    }
                }
            }

            if (!Global.Signatures.TryGetValue(record, out index))
            {
                output.Signature(methodReference, methodSignature, referenceContext, forConstructor, true);
            }
            else
            {
                output.WriteRaw("$S{0:X2}()", index);
            }
        }
Example #11
0
 public void VisitNode(JSFunctionExpression node)
 {
     if (node.Body != null)
     {
         VisitNodeInternalDown(node.Body);
         VisitNodeInternalUp(node.Body, null);
     }
 }
Example #12
0
 public void VisitNode(JSFunctionExpression node)
 {
     if (node.Body != null)
     {
         VisitNodeInternalDown(node.Body);
         VisitNodeInternalUp(node.Body, null);
     }
 }
Example #13
0
 public static JSRawOutputIdentifier ForFunction(
     JSFunctionExpression function, TypeReference type
     )
 {
     return(new JSRawOutputIdentifier(
                type,
                "$temp{0:X2}", function.TemporaryVariableCount++
                ));
 }
Example #14
0
        /// <summary>
        /// Writes an interface member reference to the output.
        /// </summary>
        public void WriteInterfaceMemberToOutput(
            JavascriptFormatter output, Compiler.Extensibility.IAstEmitter astEmitter,
            JSFunctionExpression enclosingFunction,
            JSMethod jsMethod, JSExpression method,
            TypeReferenceContext referenceContext
            )
        {
            int index;

            CachedInterfaceMemberRecord record;

            GenericParameter[] rewrittenGenericParameters = null;
            if (LocalCachingEnabled && PreferLocalCacheForGenericInterfaceMethodSignatures)
            {
                record = new CachedInterfaceMemberRecord(jsMethod.Reference.DeclaringType, jsMethod.Identifier);
            }
            else
            {
                var rewritten = GenericTypesRewriter.Normalized(jsMethod.Reference.DeclaringType);
                record = new CachedInterfaceMemberRecord(rewritten.CacheRecord, jsMethod.Identifier,
                                                         rewritten.RewritedGenericParameters.Length);
                rewrittenGenericParameters = rewritten.RewritedGenericParameters;
            }

            if (enclosingFunction.Method != null && enclosingFunction.Method.Method != null)
            {
                var      functionIdentifier = enclosingFunction.Method.Method.Identifier;
                CacheSet localSignatureSet;

                if (LocalCachedSets.TryGetValue(functionIdentifier, out localSignatureSet))
                {
                    if (localSignatureSet.InterfaceMembers.TryGetValue(record, out index))
                    {
                        output.WriteRaw("$im{0:X2}", index);

                        return;
                    }
                }
            }

            if (!Global.InterfaceMembers.TryGetValue(record, out index))
            {
                output.Identifier(jsMethod.Reference.DeclaringType, referenceContext, false);
                output.Dot();
                astEmitter.Emit(method);
            }
            else
            {
                output.WriteRaw("$IM{0:X2}", index);
                output.LPar();
                if (rewrittenGenericParameters != null)
                {
                    output.CommaSeparatedList(rewrittenGenericParameters, referenceContext);
                }
                output.RPar();
            }
        }
Example #15
0
        /// <summary>
        /// Writes a method signature to the output.
        /// </summary>
        public void WriteSignatureToOutput(
            JavascriptFormatter output, JSFunctionExpression enclosingFunction,
            MethodReference methodReference, MethodSignature methodSignature,
            TypeReferenceContext referenceContext,
            bool forConstructor
            )
        {
            int index;
            CachedSignatureRecord cacheRecord;

            GenericParameter[] rewrittenGenericParameters = null;
            if (LocalCachingEnabled && PreferLocalCacheForGenericMethodSignatures)
            {
                cacheRecord = new CachedSignatureRecord(methodReference,
                                                        GenericTypesRewriter.NormalizedConstructorSignature(methodReference, methodSignature, forConstructor),
                                                        forConstructor);
            }
            else
            {
                RewritedCacheRecord <MethodSignature> rewritten = GenericTypesRewriter.Normalized(methodReference,
                                                                                                  methodSignature, forConstructor);
                cacheRecord = new CachedSignatureRecord(methodReference, rewritten.CacheRecord, forConstructor,
                                                        rewritten.RewritedGenericParameters.Length);
                rewrittenGenericParameters = rewritten.RewritedGenericParameters;
            }

            if ((enclosingFunction.Method != null) && (enclosingFunction.Method.Method != null))
            {
                var      functionIdentifier = enclosingFunction.Method.Method.Identifier;
                CacheSet localSignatureSet;

                if (LocalCachedSets.TryGetValue(functionIdentifier, out localSignatureSet))
                {
                    if (localSignatureSet.Signatures.TryGetValue(cacheRecord, out index))
                    {
                        output.WriteRaw("$s{0:X2}", index);

                        return;
                    }
                }
            }

            if (!Global.Signatures.TryGetValue(cacheRecord, out index))
            {
                output.Signature(methodReference, methodSignature, referenceContext, forConstructor, true);
            }
            else
            {
                output.WriteRaw("$S{0:X2}", index);
                output.LPar();
                if (rewrittenGenericParameters != null)
                {
                    output.CommaSeparatedList(rewrittenGenericParameters, referenceContext);
                }
                output.RPar();
            }
        }
Example #16
0
        public FunctionCache(ITypeInfoSource typeInfo)
        {
            TypeInfo = typeInfo;
            Comparer = new QualifiedMemberIdentifier.Comparer(typeInfo);

            Cache = new ConcurrentCache <QualifiedMemberIdentifier, Entry>(
                Environment.ProcessorCount, 4096, Comparer
                );
            PendingTransformsQueue = new ConcurrentHashQueue <QualifiedMemberIdentifier>(
                Math.Max(1, Environment.ProcessorCount / 4), 4096, Comparer
                );
            ActiveTransformPipelines = new ConcurrentDictionary <QualifiedMemberIdentifier, FunctionTransformPipeline>(
                Math.Max(1, Environment.ProcessorCount / 4), 128, Comparer
                );
            MethodTypes = new MethodTypeFactory();

            MakeCacheEntry = (id, method) => {
                PendingTransformsQueue.TryEnqueue(id);

                return(new Entry(id, Locks)
                {
                    Info = method.Method,
                    Reference = method.Reference,
                    SecondPass = new FunctionAnalysis2ndPass(this, method.Method)
                });
            };

            MakePopulatedCacheEntry = (id, args) => {
                var result = new JSFunctionExpression(
                    new JSMethod(args.Method, args.Info, MethodTypes),
                    args.Translator.Variables,
                    args.Parameters,
                    args.Body,
                    MethodTypes
                    );

                PendingTransformsQueue.TryEnqueue(id);

                return(new Entry(id, Locks)
                {
                    Info = args.Info,
                    Reference = args.Method,
                    Expression = result,
                    SpecialIdentifiers = args.Translator.SpecialIdentifiers
                });
            };

            MakeNullCacheEntry = (id, args) => {
                return(new Entry(id, Locks)
                {
                    Info = args.Info,
                    Reference = args.Method,
                    Expression = null
                });
            };
        }
Example #17
0
        public static JSRawOutputIdentifier ForFunction(
            JSFunctionExpression function, TypeReference type
            )
        {
            var id = String.Format("$temp{0:X2}", function.TemporaryVariableCount++);

            return(new JSRawOutputIdentifier(
                       (jsf) => jsf.WriteRaw(id), type
                       ));
        }
Example #18
0
        public FunctionCache(ITypeInfoSource typeInfo)
        {
            var comparer = new QualifiedMemberIdentifier.Comparer(typeInfo);

            Cache = new ConcurrentCache <QualifiedMemberIdentifier, Entry>(
                Environment.ProcessorCount, 4096, comparer
                );
            OptimizationQueue = new ConcurrentHashQueue <QualifiedMemberIdentifier>(
                Math.Max(1, Environment.ProcessorCount / 4), 4096, comparer
                );
            MethodTypes = new MethodTypeFactory();

            MakeCacheEntry = (id, method) => {
                OptimizationQueue.TryEnqueue(id);

                return(new Entry {
                    Info = method.Method,
                    Reference = method.Reference,
                    Identifier = id,
                    ParameterNames = new HashSet <string>(from p in method.Method.Parameters select p.Name),
                    SecondPass = new FunctionAnalysis2ndPass(this, method.Method)
                });
            };

            MakePopulatedCacheEntry = (id, args) => {
                var result = new JSFunctionExpression(
                    new JSMethod(args.Method, args.Info, MethodTypes),
                    args.Translator.Variables,
                    args.Parameters,
                    args.Body,
                    MethodTypes
                    );

                OptimizationQueue.TryEnqueue(id);

                return(new Entry {
                    Identifier = id,
                    Info = args.Info,
                    Reference = args.Method,
                    Expression = result,
                    Variables = args.Translator.Variables,
                    ParameterNames = args.Translator.ParameterNames,
                    SpecialIdentifiers = args.Translator.SpecialIdentifiers
                });
            };

            MakeNullCacheEntry = (id, args) => {
                return(new Entry {
                    Identifier = id,
                    Info = args.Info,
                    Reference = args.Method,
                    Expression = null
                });
            };
        }
Example #19
0
        public void BuildLabelGroups(JSFunctionExpression function)
        {
            // If a label is applied to the first statement in a block, hoist it upward
            //  onto the parent block.
            var lh = new LabelHoister();

            do
            {
                lh.HoistedALabel = false;
                lh.Visit(function);
            } while (lh.HoistedALabel);

            // Walk the function to build our list of labels and gotos.
            Visit(function);

            // When a goto crosses block boundaries, we need to move the target label
            //  upwards so that the goto can reach it.
            foreach (var g in Gotos)
            {
                var targetLabel = Labels[g.TargetLabel];

                if (targetLabel.EnclosingBlock.Depth > g.EnclosingBlock.Depth)
                {
                    targetLabel.EnclosingBlock = g.EnclosingBlock;
                }
            }

            foreach (var l in Labels.Values)
            {
                l.EnsureLabelGroupExists(LabelGroups);

                var replacementGoto = new JSExpressionStatement(
                    new JSGotoExpression(l.LabelledStatement.Label)
                    );
                l.EnclosingBlock.Block.ReplaceChildRecursive(l.LabelledStatement, replacementGoto);

                l.LabelGroup.Add(l.LabelledStatement);
            }

            // If a label group only contains one label (plus an entry label),
            //  and it has a parent label group, hoist the label up.
            var lgs = new LabelGroupFlattener();

            do
            {
                lgs.FlattenedAGroup = false;
                lgs.Visit(function);
            } while (lgs.FlattenedAGroup);

            // Remove any labels within a label group that contain no statements (as long
            //  as no goto targets that label directly). This will prune empty entry/exit labels.
            var elr = new EmptyLabelRemover(UsedLabels);

            elr.Visit(function);
        }
Example #20
0
        public bool TryGetExpression(QualifiedMemberIdentifier method, out JSFunctionExpression function)
        {
            Entry entry;
            if (!Cache.TryGetValue(method, out entry)) {
                function = null;
                return false;
            }

            function = entry.Expression;
            return true;
        }
Example #21
0
        public FunctionCache(ITypeInfoSource typeInfo)
        {
            var comparer = new QualifiedMemberIdentifier.Comparer(typeInfo);
            Cache = new ConcurrentCache<QualifiedMemberIdentifier, Entry>(
                Environment.ProcessorCount, 4096, comparer
            );
            OptimizationQueue = new ConcurrentHashQueue<QualifiedMemberIdentifier>(
                Math.Max(1, Environment.ProcessorCount / 4), 4096, comparer
            );
            MethodTypes = new MethodTypeFactory();

            MakeCacheEntry = (id, method) => {
                OptimizationQueue.TryEnqueue(id);

                return new Entry {
                    Info = method.Method,
                    Reference = method.Reference,
                    Identifier = id,
                    ParameterNames = new HashSet<string>(from p in method.Method.Parameters select p.Name),
                    SecondPass = new FunctionAnalysis2ndPass(this, method.Method)
                };
            };

            MakePopulatedCacheEntry = (id, args) => {
                var result = new JSFunctionExpression(
                    new JSMethod(args.Method, args.Info, MethodTypes),
                    args.Translator.Variables,
                    args.Parameters,
                    args.Body,
                    MethodTypes
                );

                OptimizationQueue.TryEnqueue(id);

                return new Entry {
                    Identifier = id,
                    Info = args.Info,
                    Reference = args.Method,
                    Expression = result,
                    Variables = args.Translator.Variables,
                    ParameterNames = args.Translator.ParameterNames,
                    SpecialIdentifiers = args.Translator.SpecialIdentifiers
                };
            };

            MakeNullCacheEntry = (id, args) => {
                return new Entry {
                    Identifier = id,
                    Info = args.Info,
                    Reference = args.Method,
                    Expression = null
                };
            };
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            // Create a new visitor for nested function expressions
            if (Stack.OfType<JSFunctionExpression>().Skip(1).FirstOrDefault() != null) {
                var nested = new EliminatePointlessFinallyBlocks(TypeSystem, TypeInfo, FunctionSource);
                nested.Visit(fn);

                return;
            }

            VisitChildren(fn);
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            // Create a new visitor for nested function expressions
            if (Stack.OfType <JSFunctionExpression>().Skip(1).FirstOrDefault() != null)
            {
                var nested = new EliminatePointlessFinallyBlocks(TypeSystem, TypeInfo, FunctionSource);
                nested.Visit(fn);

                return;
            }

            VisitChildren(fn);
        }
Example #24
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;
            VisitChildren(fn);
        }
Example #25
0
        public bool TryGetExpression(QualifiedMemberIdentifier method, out JSFunctionExpression function)
        {
            Entry entry;

            if (!Cache.TryGet(method, out entry))
            {
                function = null;
                return(false);
            }

            function = entry.Expression;
            return(true);
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            // Create a new visitor for nested function expressions
            if (Stack.OfType<JSFunctionExpression>().Skip(1).FirstOrDefault() != null) {
                new IntroduceVariableReferences(JSIL, fn.AllVariables, new HashSet<string>(from p in fn.Parameters select p.Name)).Visit(fn);
                return;
            }

            VisitChildren(fn);

            foreach (var r in ReferencesToTransform) {
                var cr = GetConstructedReference(r);

                if (cr == null) {
                    // We have already done the variable transform for this variable in the past.
                    continue;
                }

                // For 'ref this', we need to replace each individual expression, because we can't
                //  rename the this-variable.
                if (cr.IsThis) {
                    var refThis = JSIL.NewReference(Variables["this"]);
                    fn.ReplaceChildRecursive(r, refThis);
                    continue;
                }

                var parameter = (from p in fn.Parameters
                                 where p.Identifier == cr.Identifier
                                 select p).FirstOrDefault();

                if (parameter != null) {
                    TransformParameterIntoReference(parameter, fn.Body);
                } else {
                    var declaration = (from kvp in Declarations
                                       let vds = kvp.Key
                                       from ivd in vds.Declarations.Select((vd, i) => new { vd = vd, i = i })
                                       where MatchesConstructedReference(ivd.vd.Left, cr)
                                       select new { vds = vds, vd = ivd.vd, i = ivd.i, block = kvp.Value }).FirstOrDefault();

                    if (declaration == null)
                        throw new InvalidOperationException(String.Format("Could not locate declaration for {0}", cr));

                    TransformVariableIntoReference(
                        (JSVariable)declaration.vd.Left,
                        declaration.vds,
                        declaration.i,
                        declaration.block
                    );
                }
            }
        }
Example #27
0
        public void VisitNode(JSFunctionExpression fe)
        {
            BlockStack.Push(new EnclosingBlockEntry {
                Block = fe.Body,
                ParentNode = fe,
                Depth = BlockStack.Count
            });

            try {
                VisitChildren(fe);
            } finally {
                BlockStack.Pop();
            }
        }
Example #28
0
        public FunctionAnalysis1stPass FirstPass(JSFunctionExpression function)
        {
            State = new FunctionAnalysis1stPass(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);
        }
Example #29
0
        public void VisitNode(JSFunctionExpression fe)
        {
            BlockStack.Push(new EnclosingBlockEntry {
                Block      = fe.Body,
                ParentNode = fe,
                Depth      = BlockStack.Count
            });

            try {
                VisitChildren(fe);
            } finally {
                BlockStack.Pop();
            }
        }
Example #30
0
        public JSCachedType[] CacheTypesForFunction(JSFunctionExpression function)
        {
            var currentKeys = new HashSet<GenericTypeIdentifier>(CachedTypes.Keys);

            Visit(function);

            var newKeys = new HashSet<GenericTypeIdentifier>(CachedTypes.Keys);
            newKeys.ExceptWith(currentKeys);

            return (from k in newKeys
                    let ct = CachedTypes[k]
                    orderby ct.Index
                    select ct).ToArray();
        }
Example #31
0
        public void VisitNode(JSFunctionExpression fn)
        {
            var countRefs = new CountVariableReferences(ReferenceCounts);

            countRefs.Visit(fn.Body);

            SecondPass = GetSecondPass(fn.Method);
            if (SecondPass == null)
            {
                throw new InvalidDataException("No second-pass static analysis data for function '" + fn.Method.QualifiedIdentifier + "'");
            }

            VisitChildren(fn);
        }
Example #32
0
        public JSCachedType[] CacheTypesForFunction(JSFunctionExpression function)
        {
            var currentKeys = new HashSet <GenericTypeIdentifier>(CachedTypes.Keys);

            Visit(function);

            var newKeys = new HashSet <GenericTypeIdentifier>(CachedTypes.Keys);

            newKeys.ExceptWith(currentKeys);

            return((from k in newKeys
                    let ct = CachedTypes[k]
                             orderby ct.Index
                             select ct).ToArray());
        }
Example #33
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 EmulateStructAssignment(TypeSystem, FunctionSource, CLR, OptimizeCopies);
                nested.Visit(fn);
                return;
            }

            var countRefs = new CountVariableReferences(ReferenceCounts);
            countRefs.Visit(fn.Body);

            SecondPass = FunctionSource.GetSecondPass(fn.Method);

            VisitChildren(fn);
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            if (Stack.OfType <JSFunctionExpression>().Skip(1).FirstOrDefault() != null)
            {
                var nested = new IntroduceVariableDeclarations(fn.AllVariables, TypeInfo);
                nested.Visit(fn);
                return;
            }

            var existingDeclarations = new HashSet <string>(
                fn.AllChildrenRecursive.OfType <JSVariableDeclarationStatement>()
                .SelectMany(
                    (vds) =>
                    from vd in vds.Declarations
                    select((JSVariable)vd.Left).Identifier
                    ).Union(
                    from tcb in fn.AllChildrenRecursive.OfType <JSTryCatchBlock>()
                    where tcb.CatchVariable != null
                    select tcb.CatchVariable.Identifier
                    )
                );

            foreach (var v_ in from v in Variables.Values
                     where !v.IsParameter &&
                     !existingDeclarations.Contains(v.Identifier)
                     select v)
            {
                ToDeclare.Add(v_);
            }

            VisitChildren(fn);

            if (ToDeclare.Count > 0)
            {
                fn.Body.Statements.Insert(
                    0, new JSVariableDeclarationStatement(
                        (from v in ToDeclare
                         select new JSBinaryOperatorExpression(
                             JSOperator.Assignment, v,
                             v.DefaultValue,
                             v.Type
                             )).ToArray()
                        )
                    );
            }
        }
Example #35
0
        public void BuildLabelGroups(JSFunctionExpression function)
        {
            // If a label is applied to the first statement in a block, hoist it upward
            //  onto the parent block.
            var lh = new LabelHoister();
            do {
                lh.HoistedALabel = false;
                lh.Visit(function);
            } while (lh.HoistedALabel);

            // Walk the function to build our list of labels and gotos.
            Visit(function);

            // When a goto crosses block boundaries, we need to move the target label
            //  upwards so that the goto can reach it.
            foreach (var g in Gotos) {
                var targetLabel = Labels[g.TargetLabel];

                if (targetLabel.EnclosingBlock.Depth > g.EnclosingBlock.Depth)
                    targetLabel.EnclosingBlock = g.EnclosingBlock;
            }

            foreach (var l in Labels.Values) {
                l.EnsureLabelGroupExists(LabelGroups);

                var replacementGoto = new JSExpressionStatement(
                    new JSGotoExpression(l.LabelledStatement.Label)
                );
                l.EnclosingBlock.Block.ReplaceChildRecursive(l.LabelledStatement, replacementGoto);

                l.LabelGroup.Add(l.LabelledStatement);
            }

            // If a label group only contains one label (plus an entry label),
            //  and it has a parent label group, hoist the label up.
            var lgs = new LabelGroupFlattener();
            do {
                lgs.FlattenedAGroup = false;
                lgs.Visit(function);
            } while (lgs.FlattenedAGroup);

            // Remove any labels within a label group that contain no statements (as long
            //  as no goto targets that label directly). This will prune empty entry/exit labels.
            var elr = new EmptyLabelRemover(UsedLabels);
            elr.Visit(function);
        }
Example #36
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 EmulateStructAssignment(TypeSystem, FunctionSource, CLR, OptimizeCopies);
                nested.Visit(fn);
                return;
            }

            var countRefs = new CountVariableReferences(ReferenceCounts);

            countRefs.Visit(fn.Body);

            SecondPass = FunctionSource.GetSecondPass(fn.Method);

            VisitChildren(fn);
        }
Example #37
0
        public void VisitNode(JSFunctionExpression fn)
        {
            var existingDeclarations = new HashSet <string>(
                fn.AllChildrenRecursive.OfType <JSVariableDeclarationStatement>()
                .SelectMany(
                    (vds) =>
                    from vd in vds.Declarations
                    select((JSVariable)vd.Left).Identifier
                    ).Union(
                    from tcb in fn.AllChildrenRecursive.OfType <JSTryCatchBlock>()
                    where tcb.CatchVariable != null
                    select tcb.CatchVariable.Identifier
                    )
                );

            foreach (var v_ in from v in Variables.Values
                     where !v.IsParameter &&
                     !existingDeclarations.Contains(v.Identifier)
                     select v)
            {
                ToDeclare.Add(v_);
            }

            VisitChildren(fn);

            foreach (var kvp in ToReplace)
            {
                fn.ReplaceChildRecursive(kvp.Key, kvp.Value);
            }

            if (ToDeclare.Count > 0)
            {
                fn.Body.Statements.Insert(
                    0, new JSVariableDeclarationStatement(
                        (from v in ToDeclare
                         select new JSBinaryOperatorExpression(
                             JSOperator.Assignment, v,
                             v.DefaultValue,
                             v.IdentifierType
                             )).ToArray()
                        )
                    );
            }
        }
Example #38
0
        public void VisitNode(JSFunctionExpression fe)
        {
            FunctionStack.Push(fe);

            try {
                VisitChildren(fe);
            } finally {
                var      functionIdentifier = fe.Method.Method.Identifier;
                CacheSet localSet;
                if (LocalCachedSets.TryGetValue(functionIdentifier, out localSet))
                {
                    var trType = fe.Method.Reference.Module.TypeSystem.SystemType();

                    int i = 0;
                    foreach (var kvp in localSet.Signatures)
                    {
                        var record = kvp.Key;
                        var stmt   = new JSVariableDeclarationStatement(new JSBinaryOperatorExpression(
                                                                            JSOperator.Assignment,
                                                                            MakeRawOutputIdentifierForIndex(trType, kvp.Value, true),
                                                                            new JSLocalCachedSignatureExpression(trType, record.Method, record.Signature, record.IsConstructor),
                                                                            trType
                                                                            ));

                        fe.Body.Statements.Insert(i++, stmt);
                    }

                    foreach (var kvp in localSet.InterfaceMembers)
                    {
                        var record = kvp.Key;
                        var stmt   = new JSVariableDeclarationStatement(new JSBinaryOperatorExpression(
                                                                            JSOperator.Assignment,
                                                                            MakeRawOutputIdentifierForIndex(trType, kvp.Value, false),
                                                                            new JSLocalCachedInterfaceMemberExpression(trType, record.InterfaceType, record.InterfaceMember),
                                                                            trType
                                                                            ));

                        fe.Body.Statements.Insert(i++, stmt);
                    }
                }

                FunctionStack.Pop();
            }
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            if (Stack.OfType<JSFunctionExpression>().Skip(1).FirstOrDefault() != null) {
                var nested = new IntroduceVariableDeclarations(fn.AllVariables, TypeInfo);
                nested.Visit(fn);
                return;
            }

            var existingDeclarations = new HashSet<string>(
                fn.AllChildrenRecursive.OfType<JSVariableDeclarationStatement>()
                .SelectMany(
                    (vds) =>
                        from vd in vds.Declarations
                        select ((JSVariable)vd.Left).Identifier
                ).Union(
                    from tcb in fn.AllChildrenRecursive.OfType<JSTryCatchBlock>()
                    where tcb.CatchVariable != null
                    select tcb.CatchVariable.Identifier
                )
            );

            foreach (var v_ in from v in Variables.Values
                               where !v.IsParameter &&
                                     !existingDeclarations.Contains(v.Identifier)
                               select v)
            {
                ToDeclare.Add(v_);
            }

            VisitChildren(fn);

            if (ToDeclare.Count > 0)
                fn.Body.Statements.Insert(
                    0, new JSVariableDeclarationStatement(
                        (from v in ToDeclare
                         select new JSBinaryOperatorExpression(
                            JSOperator.Assignment, v,
                            v.DefaultValue,
                            v.IdentifierType
                        )).ToArray()
                    )
                );
        }
Example #40
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);
                    }
                }
            }
        }
Example #41
0
        public void VisitNode(JSFunctionExpression fn)
        {
            // Create a new visitor for nested function expressions
            if (Stack.OfType<JSFunctionExpression>().Skip(1).FirstOrDefault() != null) {
                new IntroduceVariableReferences(JSIL, fn.AllVariables, new HashSet<string>(from p in fn.Parameters select p.Name)).Visit(fn);
                return;
            }

            VisitChildren(fn);

            foreach (var r in ReferencesToTransform) {
                var cr = GetConstructedReference(r);

                if (cr == null) {
                    // We have already done the variable transform for this variable in the past.
                    continue;
                }

                var parameter = (from p in fn.Parameters
                                 where p.Identifier == cr.Identifier
                                 select p).FirstOrDefault();

                if (parameter != null) {
                    TransformParameterIntoReference(parameter, fn.Body);
                } else {
                    var declaration = (from vds in Declarations
                                       from ivd in vds.Declarations.Select((vd, i) => new { vd = vd, i = i })
                                       where MatchesConstructedReference(ivd.vd.Left, cr)
                                       select new { vds = vds, vd = ivd.vd, i = ivd.i }).FirstOrDefault();

                    if (declaration == null)
                        throw new InvalidOperationException(String.Format("Could not locate declaration for {0}", cr));

                    TransformVariableIntoReference(
                        (JSVariable)declaration.vd.Left,
                        declaration.vds,
                        declaration.i
                    );
                }
            }
        }
        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);
                    }
                }
            }
        }
        public void VisitNode (JSFunctionExpression fn) {
            var existingDeclarations = new HashSet<string>(
                fn.AllChildrenRecursive.OfType<JSVariableDeclarationStatement>()
                .SelectMany(
                    (vds) => 
                        from vd in vds.Declarations 
                        select ((JSVariable)vd.Left).Identifier
                ).Union(
                    from tcb in fn.AllChildrenRecursive.OfType<JSTryCatchBlock>()
                    where tcb.CatchVariable != null
                    select tcb.CatchVariable.Identifier
                )
            );

            foreach (var v_ in from v in Variables.Values
                               where !v.IsParameter &&
                                     !existingDeclarations.Contains(v.Identifier)
                               select v) 
            {
                ToDeclare.Add(v_);
            }

            VisitChildren(fn);

            foreach (var kvp in ToReplace)
                fn.ReplaceChildRecursive(kvp.Key, kvp.Value);

            if (ToDeclare.Count > 0)
                fn.Body.Statements.Insert(
                    0, new JSVariableDeclarationStatement(
                        (from v in ToDeclare
                         select new JSBinaryOperatorExpression(
                            JSOperator.Assignment, v,
                            v.DefaultValue, 
                            v.IdentifierType
                        )).ToArray()
                    )
                );
        }
Example #44
0
        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,
                            new JSDefaultValueLiteral(pd.Type),
                            pd.Type
                    ));

                    fn.Body.Statements.Insert(i++, es);
                }
            }
        }
Example #45
0
        public void VisitNode(JSFunctionExpression function)
        {
            var oldCurrentMethod = Output.CurrentMethod;

            if (function.Method != null)
            {
                Output.CurrentMethod = function.Method.Reference;
            }
            else
            {
                Output.CurrentMethod = null;
            }

            Output.OpenFunction(
                function.DisplayName,
                (o) => o.WriteParameterList(function.Parameters)
                );

            Visit(function.Body);

            Output.CloseBrace(false);
            Output.CurrentMethod = oldCurrentMethod;
        }
Example #46
0
        /// <summary>
        /// Writes an interface member reference to the output.
        /// </summary>
        public void WriteInterfaceMemberToOutput(
            JavascriptFormatter output, JavascriptAstEmitter emitter, JSFunctionExpression enclosingFunction,
            JSMethod jsMethod, JSExpression method,
            TypeReferenceContext referenceContext
            )
        {
            int index;
            var record = new CachedInterfaceMemberRecord(jsMethod.Reference.DeclaringType, jsMethod.Identifier);

            if ((enclosingFunction.Method != null) || (enclosingFunction.Method.Method != null))
            {
                var      functionIdentifier = enclosingFunction.Method.Method.Identifier;
                CacheSet localSignatureSet;

                if (LocalCachedSets.TryGetValue(functionIdentifier, out localSignatureSet))
                {
                    if (localSignatureSet.InterfaceMembers.TryGetValue(record, out index))
                    {
                        output.WriteRaw("$im{0:X2}", index);

                        return;
                    }
                }
            }

            if (!Global.InterfaceMembers.TryGetValue(record, out index))
            {
                output.Identifier(jsMethod.Reference.DeclaringType, referenceContext, false);
                output.Dot();
                emitter.Visit(method);
            }
            else
            {
                output.WriteRaw("$IM{0:X2}()", index);
            }
        }
Example #47
0
        public FunctionTransformPipeline(
            AssemblyTranslator translator,
            QualifiedMemberIdentifier identifier, JSFunctionExpression function,
            SpecialIdentifiers si
            )
        {
            Translator         = translator;
            Identifier         = identifier;
            Function           = function;
            SpecialIdentifiers = si;

            FillPipeline();

            if (!Translator.FunctionCache.ActiveTransformPipelines.TryAdd(Identifier, this))
            {
                throw new ThreadStateException();
            }

            if (CheckForStaticAnalysisChanges)
            {
                OriginalFunctionBody = Function.Body.ToString();
                OriginalSecondPass   = Translator.FunctionCache.GetSecondPass(function.Method, function.Method.QualifiedIdentifier);
            }
        }
        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;
                }

                if (replacement.SelfAndChildrenRecursive.OfType<JSBinaryOperatorExpression>().Any(boe => boe.Operator is JSAssignmentOperator)) {
                    if (TraceLevel >= 2)
                        Console.WriteLine("Cannot eliminate {0}; it contains an assignment.", 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 (CanSkipUsageVeto(replacement)) {
                        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;
                }
            }
        }
        public void VisitNode (JSFunctionExpression fn) {
            var countRefs = new CountVariableReferences(ReferenceCounts);
            countRefs.Visit(fn.Body);

            SecondPass = GetSecondPass(fn.Method);
            if (SecondPass == null)
                throw new InvalidDataException("No second-pass static analysis data for function '" + fn.Method.QualifiedIdentifier + "'");

            VisitChildren(fn);
        }
Example #50
0
        private void OptimizeFunction(
            SpecialIdentifiers si, HashSet<string> parameterNames,
            Dictionary<string, JSVariable> variables, JSFunctionExpression function
        )
        {
            // Run elimination repeatedly, since eliminating one variable may make it possible to eliminate others
            if (EliminateTemporaries) {
                bool eliminated;
                do {
                    var visitor = new EliminateSingleUseTemporaries(
                        si.TypeSystem, variables, FunctionCache
                    );
                    visitor.Visit(function);
                    eliminated = visitor.EliminatedVariables.Count > 0;
                } while (eliminated);
            }

            new EmulateStructAssignment(
                si.TypeSystem,
                FunctionCache,
                si.CLR,
                OptimizeStructCopies
            ).Visit(function);

            new IntroduceVariableDeclarations(
                variables,
                TypeInfoProvider
            ).Visit(function);

            new IntroduceVariableReferences(
                si.JSIL,
                variables,
                parameterNames
            ).Visit(function);

            if (SimplifyLoops)
                new SimplifyLoops(
                    si.TypeSystem
                ).Visit(function);

            // Temporary elimination makes it possible to simplify more operators, so do it last
            if (SimplifyOperators)
                new SimplifyOperators(
                    si.JSIL, si.JS, si.TypeSystem
                ).Visit(function);

            new IntroduceEnumCasts(
                si.TypeSystem
            ).Visit(function);
        }
Example #51
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);
            }
        }
        public void VisitNode (JSFunctionExpression function) {
            Function = function;

            VisitChildren(function);
        }
Example #53
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 EmulateStructAssignment(TypeSystem, CLR);
                nested.Visit(fn);
                return;
            }

            var countRefs = new CountVariableReferences(ReferenceCounts);
            countRefs.Visit(fn);

            VisitChildren(fn);
        }
        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.Identifier);
            if (FirstPass == null)
                throw new InvalidOperationException();

            VisitChildren(fn);

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

                var valueType = v.GetExpectedType(TypeSystem);
                if (ILBlockTranslator.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();

                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));
                    } else {
                        if (TraceLevel >= 2)
                            Debug.WriteLine(String.Format("Never found an initial assignment for {0}.", 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 ((from a in FirstPass.Assignments where v.Equals(a.Target) && a.IsConversion select a).FirstOrDefault() != null) {
                    if (TraceLevel >= 2)
                        Debug.WriteLine(String.Format("Cannot eliminate {0}; it undergoes type conversion.", 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.AllChildrenRecursive.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.StatementIndex, access.NodeIndex,
                            transferDataTo, access.IsControlFlow
                        ));
                    }

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

                       ));
                    }
                }

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

                EliminatedVariables.Add(v);

                EliminateVariable(fn, v, replacement);
            }
        }
Example #55
0
        public FunctionCache (ITypeInfoSource typeInfo) {
            TypeInfo = typeInfo;
            Comparer = new QualifiedMemberIdentifier.Comparer(typeInfo);

            Cache = new ConcurrentCache<QualifiedMemberIdentifier, Entry>(
                Environment.ProcessorCount, 4096, Comparer
            );
            PendingTransformsQueue = new ConcurrentHashQueue<QualifiedMemberIdentifier>(
                Math.Max(1, Environment.ProcessorCount / 4), 4096, Comparer
            );
            ActiveTransformPipelines = new ConcurrentDictionary<QualifiedMemberIdentifier, FunctionTransformPipeline>(
                Math.Max(1, Environment.ProcessorCount / 4), 128, Comparer
            );
            MethodTypes = new MethodTypeFactory();

            MakeCacheEntry = (id, method) => {
                PendingTransformsQueue.TryEnqueue(id);

                return new Entry(id, Locks) {
                    Info = method.Method,
                    Reference = method.Reference,
                    SecondPass = new FunctionAnalysis2ndPass(this, method.Method)
                };
            };

            MakePopulatedCacheEntry = (id, args) => {
                var result = new JSFunctionExpression(
                    new JSMethod(args.Method, args.Info, MethodTypes),
                    args.Translator.Variables,
                    args.Parameters,
                    args.Body,
                    MethodTypes
                );

                PendingTransformsQueue.TryEnqueue(id);

                return new Entry(id, Locks) {
                    Info = args.Info,
                    Reference = args.Method,
                    Expression = result,
                    SpecialIdentifiers = args.Translator.SpecialIdentifiers
                };
            };

            MakeNullCacheEntry = (id, args) =>
                new Entry(id, Locks) {
                    Info = args.Info,
                    Reference = args.Method,
                    Expression = null
                };
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            VisitChildren(fn);

            foreach (var p in fn.Parameters) {
                if (!p.IsReference)
                    continue;

                var vrat = new VariableReferenceAccessTransformer(JSIL, p);
                vrat.Visit(fn);
            }

            /*
            if (!fn.Method.Method.IsStatic) {
                var vrat = new VariableReferenceAccessTransformer(JSIL, Variables["this"]);
                vrat.Visit(fn);
            }
             */

            foreach (var r in ReferencesToTransform) {
                var cr = GetConstructedReference(r);

                if (cr == null) {
                    // We have already done the variable transform for this variable in the past.
                    continue;
                }

                // For 'ref this', we need to replace each individual expression, because we can't
                //  rename the this-variable.
                if (cr.IsThis) {
                    var refThis = JSIL.NewReference(Variables["this"]);
                    fn.ReplaceChildRecursive(r, refThis);
                    continue;
                }

                var parameter = (from p in fn.Parameters
                                 where p.Identifier == cr.Identifier
                                 select p).FirstOrDefault();

                if (parameter != null) {
                    TransformParameterIntoReference(parameter, fn.Body);
                } else {
                    var declaration = (from kvp in Declarations
                                       let vds = kvp.Key
                                       from ivd in vds.Declarations.Select((vd, i) => new { vd = vd, i = i })
                                       where MatchesConstructedReference(ivd.vd.Left, cr)
                                       select new { vds = vds, vd = ivd.vd, i = ivd.i, block = kvp.Value }).FirstOrDefault();

                    if (declaration == null)
                        throw new InvalidOperationException(String.Format("Could not locate declaration for {0}", cr));

                    TransformVariableIntoReference(
                        (JSVariable)declaration.vd.Left,
                        declaration.vds,
                        declaration.i,
                        declaration.block
                    );
                }

                var vrat = new VariableReferenceAccessTransformer(JSIL, cr);
                vrat.Visit(fn);
            }
        }
        public void VisitNode(JSFunctionExpression fn)
        {
            var nullList = new List<int>();
            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
                ));

            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 reassignments = (from a in FirstPass.Assignments where v.Equals(a.SourceVariable) 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) && (invocations.Length == 0) && (reassignments.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);

                        // We've invalidated the static analysis data so the best choice is to abort.
                        break;
                    } 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));

                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;
            }
        }
Example #58
0
        internal JSFunctionExpression Create(
            MethodInfo info, MethodDefinition methodDef, MethodReference method, 
            QualifiedMemberIdentifier identifier, ILBlockTranslator translator, 
            IEnumerable<JSVariable> parameters, JSBlockStatement body
        )
        {
            var result = new JSFunctionExpression(
                new JSMethod(method, info),
                translator.Variables,
                parameters,
                body
            );

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

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

            return result;
        }
Example #59
0
 public void CacheMethodsForFunction (JSFunctionExpression function) {
     Visit(function);
 }
Example #60
0
        public void EmitFunctionBody (IAstEmitter astEmitter, MethodDefinition method, JSFunctionExpression function) {
            astEmitter.ReferenceContext.Push();
            astEmitter.ReferenceContext.EnclosingMethod = method;

            try {
                astEmitter.Emit(function);
            } catch (Exception exc) {
                throw new Exception("Error occurred while generating javascript for method '" + method.FullName + "'.", exc);
            } finally {
                astEmitter.ReferenceContext.Pop();
            }

            EmitSemicolon();
            EmitSpacer();
        }