Example #1
0
        public IReadOnlyCollection <MethodDef> GetImplementations(MethodUniqueSignature signature,
                                                                  HashSet <TypeDef> types)
        {
            if (!implementations.TryGetValue(signature, out var methods))
            {
                return(Array.Empty <MethodDef>());
            }

            if (types != null)
            {
                var filteredMethods = new List <MethodDef>(methods.Count);
                foreach (var method in methods)
                {
                    if (types.Contains(method.DeclaringType))
                    {
                        filteredMethods.Add(method);
                    }
                }

                return(filteredMethods);
            }

            Debug.Assert(methods.Count > 0);
            return(methods);
        }
Example #2
0
 public ProcessingEntity(MethodUniqueSignature signature, ICallGraphNode node,
                         bool virtCallRequired = false)
 {
     Signature        = signature;
     Node             = node;
     VirtCallRequired = virtCallRequired;
 }
Example #3
0
        public IReadOnlyCollection <MethodDef> GetImplementations(MethodUniqueSignature signature,
                                                                  string entryPointAssemblyName = null)
        {
            if (!implementations.TryGetValue(signature, out var methods))
            {
                return(Array.Empty <MethodDef>());
            }

            if (entryPointAssemblyName != null)
            {
                var references      = AssemblyReferences[entryPointAssemblyName];
                var filteredMethods = new List <MethodDef>(methods.Count);
                foreach (var method in methods)
                {
                    var assemblyName = method.DeclaringType.DefinitionAssembly.Name;
                    if (entryPointAssemblyName == assemblyName ||
                        references.Contains(assemblyName))
                    {
                        filteredMethods.Add(method);
                    }
                }

                return(filteredMethods);
            }

            Debug.Assert(methods.Count > 0);
            return(methods);
        }
Example #4
0
        public int GetImplementationsCount(MethodUniqueSignature signature,
                                           string entryPointAssemblyName = null)
        {
            if (!implementations.TryGetValue(signature, out var methods))
            {
                return(0);
            }

            if (entryPointAssemblyName != null)
            {
                var references = AssemblyReferences[entryPointAssemblyName];
                var count      = 0;
                foreach (var method in methods)
                {
                    var assemblyName = method.DeclaringType.DefinitionAssembly.Name;
                    if (entryPointAssemblyName == assemblyName ||
                        references.Contains(assemblyName))
                    {
                        count++;
                    }
                }

                return(count);
            }

            Debug.Assert(methods.Count > 0);
            return(methods.Count);
        }
Example #5
0
 public CallInfo(int instructionIndex, MethodDef methodDef,
                 AssemblyInfo assemblyInfo,
                 MethodUniqueSignature signature,
                 bool isPublic,
                 List <MethodUniqueSignature> overrideSignatures)
 {
     this.methodDef        = methodDef;
     this.instructionIndex = instructionIndex;
     AssemblyInfo          = assemblyInfo;
     Signature             = signature;
     IsPublic           = isPublic;
     OverrideSignatures = overrideSignatures;
     Opcode             = methodDef != null
         ? methodDef.Body.Instructions[instructionIndex].OpCode
         : OpCodes.Call;
 }
Example #6
0
        public List <CallInfo> GetCalls(MethodUniqueSignature methodSignature, AssemblyInfo assemblyInfo)
        {
            if (assemblyInfo == null ||
                assemblyInfo.Name == (UTF8String)null ||
                assemblyInfo.Name == UTF8String.Empty ||
                assemblyInfo.Version == null ||
                assemblyInfo.Version == AssemblyInfo.EmptyVersion)
            {
                return(GetCalls(methodSignature));
            }

            if (callers.TryGetValue(methodSignature, out var callInfoMap))
            {
                return(callInfoMap[assemblyInfo]);
            }

            return(empty);
        }
Example #7
0
        // TODO: use IReadOnlyCollection<CallInfo>
        public List <CallInfo> GetCalls(MethodUniqueSignature methodSignature)
        {
            if (callers.TryGetValue(methodSignature, out var callInfoMap))
            {
                if (callInfoMap.Count == 1)
                {
                    return(callInfoMap.Values.First());
                }

                var result = new List <CallInfo>();
                foreach (var list in callInfoMap.Values)
                {
                    result.AddRange(list);
                }

                return(result);
            }

            return(empty);
        }
Example #8
0
        public int GetImplementationsCount(MethodUniqueSignature signature, HashSet <TypeDef> types)
        {
            if (!implementations.TryGetValue(signature, out var methods))
            {
                return(0);
            }

            if (types != null)
            {
                var count = 0;
                foreach (var method in methods)
                {
                    if (types.Contains(method.DeclaringType))
                    {
                        count++;
                    }
                }

                return(count);
            }

            Debug.Assert(methods.Count > 0);
            return(methods.Count);
        }
Example #9
0
 public TemplateInfo(MethodUniqueSignature method, Version requiredOlderVersion)
 {
     Method = method;
     RequiredOlderVersion = requiredOlderVersion;
 }
Example #10
0
        public void RemoveSameClasses()
        {
            var handledNodes    = new HashSet <ICallGraphNode>(Nodes.Count);
            var processingNodes = new Queue <(ICallGraphNode, ICallGraphNode)>();

            EntryNodes.Clear();
            Nodes.Clear();
            var roots = Roots.Values;

            Roots = new Dictionary <MethodUniqueSignature, ICallGraphNode>();
            foreach (var rootNode in roots)
            {
                // we keep all parents of root(s)
                if (!handledNodes.Add(rootNode))
                {
                    continue;
                }

                var mappedRootNode = new CallInfoNode(rootNode.Info);
                Roots.Add(mappedRootNode.MethodSignature, mappedRootNode);
                Nodes.Add(mappedRootNode.MethodSignature, mappedRootNode);
                if (rootNode.InNodes.Count == 0 && !EntryNodes.ContainsKey(mappedRootNode.MethodSignature))
                {
                    EntryNodes.Add(mappedRootNode.MethodSignature, mappedRootNode);
                }

                foreach (var inNode in rootNode.InNodes)
                {
                    var mappedNode = new CallInfoNode(inNode.Info);
                    mappedRootNode.InNodes.Add(mappedNode);
                    mappedNode.OutNodes.Add(mappedRootNode);

                    if (!Nodes.ContainsKey(mappedNode.MethodSignature))
                    {
                        Nodes.Add(mappedNode.MethodSignature, mappedNode);
                        if (inNode.InNodes.Count == 0)
                        {
                            if (!EntryNodes.ContainsKey(mappedNode.MethodSignature))
                            {
                                EntryNodes.Add(mappedNode.MethodSignature, mappedNode);
                            }
                        }
                        else
                        {
                            processingNodes.Enqueue((inNode, mappedNode));
                        }
                    }
                }
            }

            // and keep only different classes for other parents
            while (processingNodes.Count > 0)
            {
                var(node, mappedNode) = processingNodes.Dequeue();
                if (!handledNodes.Add(node))
                {
                    continue;
                }

                var mappedInNodes = new HashSet <ICallGraphNode>(mappedNode.InNodes);
                foreach (var inNode in node.InNodes)
                {
                    var classSignature = new MethodUniqueSignature(inNode.MethodSignature.ToClassName());
                    if (Nodes.TryGetValue(classSignature, out var mappedInNode))
                    {
                        if (mappedInNode != mappedNode && mappedInNodes.Add(mappedInNode))
                        {
                            mappedInNode.OutNodes.Add(mappedNode);
                        }
                    }
                    else
                    {
                        mappedInNode = new CallInfoNode(new CallInfo(
                                                            0,
                                                            null,
                                                            inNode.AssemblyInfo,
                                                            classSignature,
                                                            inNode.IsPublic,
                                                            null));

                        mappedInNodes.Add(mappedInNode);
                        mappedInNode.OutNodes.Add(mappedNode);
                        Nodes.Add(mappedInNode.MethodSignature, mappedInNode);
                    }

                    if (inNode.InNodes.Count == 0)
                    {
                        if (!EntryNodes.ContainsKey(mappedInNode.MethodSignature))
                        {
                            EntryNodes.Add(mappedInNode.MethodSignature, mappedInNode);
                        }
                    }
                    else
                    {
                        processingNodes.Enqueue((inNode, mappedInNode));
                    }
                }

                if (mappedNode.InNodes.Count != mappedInNodes.Count)
                {
                    mappedNode.InNodes.Clear();
                    mappedNode.InNodes.AddRange(mappedInNodes);
                }
            }
        }
Example #11
0
 public static CallInfo CreateFake(AssemblyInfo assemblyInfo, MethodUniqueSignature signature) =>
 new CallInfo(0, null,
              assemblyInfo,
              signature,
              true,
              new List <MethodUniqueSignature>(0));
Example #12
0
 private bool Equals(MethodUniqueSignature other)
 {
     return(string.Equals(fullName, other.fullName));
 }
Example #13
0
        private bool TryGetConcreteSignature(MethodDef methodDef, int index, out MethodUniqueSignature signature)
        {
            signature = null;

            var instructions = methodDef.Body.Instructions;

            Debug.Assert(instructions[index].OpCode.Code == Code.Callvirt);
            var method = (IMethod)instructions[index].Operand;

            if (method.DeclaringType.ContainsGenericParameter ||  // because we can lose info about <T> when 'this' arg is returned from another call
                method.DeclaringType.FullName == "System.Array")  // because type.ResolveTypeDef() returns type of an element (e.g., w/o [])
            {
                return(false);
            }

            Debug.Assert(method.MethodSig.ImplicitThis);
            var pushedStackSlots = method.GetParameterCount();

            // try to rollback to an instruction that pushes 'this'
            while (index > 0 && pushedStackSlots > 0)
            {
                var instruction = instructions[--index];
                if (instruction.OpCode.FlowControl != FlowControl.Call &&
                    instruction.OpCode.FlowControl != FlowControl.Meta &&
                    instruction.OpCode.FlowControl != FlowControl.Next)
                {
                    // not supported instruction
                    //Console.WriteLine($"Not supported FlowControl in TryGetConcreteSignature(): {instruction}");
                    return(false);
                }

                instruction.CalculateStackUsage(out var pushes, out var pops);
                pushedStackSlots -= pushes;
                if (pushedStackSlots == 0)
                {
                    // check instruction
                    if (instruction.TryGetPushedType(methodDef, out var type))
                    {
                        while (type != null &&
                               type != method.DeclaringType &&
                               type.FullName != method.DeclaringType.FullName)
                        {
                            var typeDef = type.ResolveTypeDef();
                            if (typeDef == null)
                            {
                                return(false);
                            }

                            var overriddenMethod = typeDef.FindMethod(method.Name, method.MethodSig);
                            if (overriddenMethod != null)
                            {
                                signature = overriddenMethod.CreateMethodUniqueSignature();
                                return(true);
                            }

                            type = typeDef.BaseType;
                        }
                    }

                    return(false);
                }

                pushedStackSlots += pops;
            }

            return(false);
        }
Example #14
0
        private List <TypeDef> BuildIndexes(List <ModuleDefMD> modules, HashSet <string> convertingTypes)
        {
            var result     = new List <TypeDef>();
            var references = new Dictionary <string, List <string> >(modules.Count);

            foreach (var module in modules)
            {
                references.Add(
                    module.Assembly.Name,
                    module.GetAssemblyRefs().Select(x => x.Name.ToString()).ToList());

                /*
                 * var currentAssemblyName = module.Assembly.Name.ToString();
                 * var foundRefs = false;
                 * foreach (var assemblyRef in module.GetAssemblyRefs())
                 * {
                 *  var name = assemblyRef.Name;
                 *  if (references.TryGetValue(name, out var list))
                 *  {
                 *      list.Add(currentAssemblyName);
                 *  }
                 *  else
                 *  {
                 *      references.Add(name, new HashSet<string>{currentAssemblyName});
                 *  }
                 *
                 *  foundRefs = true;
                 * }
                 *
                 * if (!foundRefs)
                 * {
                 *  rootReferences.Add(currentAssemblyName);
                 * }
                 */

                foreach (var typeDef in module.GetTypes())
                {
                    if (convertingTypes.Contains(typeDef.FullName /*typeDef.ReflectionFullName*/))
                    {
                        result.Add(typeDef);
                    }

                    stat.TypeCount++;
                    if (!typeDef.HasMethods)
                    {
                        continue;
                    }

                    foreach (var methodDef in typeDef.Methods)
                    {
                        stat.MethodCount++;
                        if (!methodDef.HasBody)
                        {
                            continue;
                        }
                        if (!methodDef.Body.HasInstructions)
                        {
                            continue;
                        }

                        stat.InstructionCount += methodDef.Body.Instructions.Count;
                        var cachedOverrides = methodDef.FindOverrides();
                        AddImplementations(methodDef, cachedOverrides);

                        CallInfo cacheInfo = null;
                        for (var index = 0; index < methodDef.Body.Instructions.Count; index++)
                        {
                            var instruction = methodDef.Body.Instructions[index];
                            if (instruction.OpCode == OpCodes.Ldsfld ||
                                instruction.OpCode == OpCodes.Ldfld ||
                                instruction.OpCode == OpCodes.Ldsflda ||
                                instruction.OpCode == OpCodes.Ldflda ||
                                instruction.OpCode == OpCodes.Stsfld ||
                                instruction.OpCode == OpCodes.Stfld)
                            {
                                continue;
                            }

                            // TODO: check opcodes:
                            //    + call: 802655
                            //    + callvirt: 918700
                            //    + newobj: 255686
                            //    - ldsfld: 27607
                            //    - ldfld: 57948
                            //    - stfld: 23493
                            //    ? ldftn: 41261
                            //    - ldflda: 4556
                            //    ? ldvirtftn: 1453
                            //    - stsfld: 2023
                            //    ? ldtoken: 622
                            //    - ldsflda: 24
                            if (instruction.Operand is IMethod methodOperand)
                            {
                                if (methodOperand.DeclaringType.DefinitionAssembly == null)
                                {
                                    // TODO: it is possible for an array of generic type, just skip it for now
                                    // FSharp.Core.dll
                                    // T[0...,0...] Microsoft.FSharp.Core.ExtraTopLevelOperators::array2D$cont@115<?,T>(?[],System.Int32,Microsoft.FSharp.Core.Unit)
                                    continue;
                                }

                                stat.MethodCallCount++;

                                CallInfo newInfo;
                                if (cacheInfo == null)
                                {
                                    newInfo   = new CallInfo(index, methodDef, cachedOverrides);
                                    cacheInfo = newInfo;
                                }
                                else
                                {
                                    newInfo = cacheInfo.Copy(index);
                                }

                                // TODO PERF add cache for AssemblyInfo
                                var assemblyInfo = new AssemblyInfo(
                                    methodOperand.DeclaringType.DefinitionAssembly.Name,
                                    methodOperand.DeclaringType.DefinitionAssembly.Version);

                                MethodUniqueSignature key = null;
                                if (instruction.OpCode.Code == Code.Callvirt)
                                {
                                    if (TryGetConcreteSignature(methodDef, index, out key))
                                    {
                                        stat.SpecifiedVirtualCalls++;
                                        newInfo.Opcode = OpCodes.Call;
                                    }
                                }

                                if (key == null)
                                {
                                    key = methodOperand.CreateMethodUniqueSignature();
                                }

                                if (callers.TryGetValue(key, out var callInfoMap))
                                {
                                    if (callInfoMap.TryGetValue(assemblyInfo, out var list))
                                    {
                                        list.Add(newInfo);
                                    }
                                    else
                                    {
                                        callInfoMap.Add(assemblyInfo, new List <CallInfo> {
                                            newInfo
                                        });
                                    }
                                }
                                else
                                {
                                    callers.Add(key, new Dictionary <AssemblyInfo, List <CallInfo> >()
                                    {
                                        { assemblyInfo, new List <CallInfo> {
                                              newInfo
                                          } }
                                    });
                                }
                            }
                        }
                    }
                }
            }

            foreach (var refAssembly in references.Keys)
            {
                CacheReferences(refAssembly, references);
            }

            return(result);
        }