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); }
public ProcessingEntity(MethodUniqueSignature signature, ICallGraphNode node, bool virtCallRequired = false) { Signature = signature; Node = node; VirtCallRequired = virtCallRequired; }
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); }
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); }
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; }
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); }
// 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); }
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); }
public TemplateInfo(MethodUniqueSignature method, Version requiredOlderVersion) { Method = method; RequiredOlderVersion = requiredOlderVersion; }
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); } } }
public static CallInfo CreateFake(AssemblyInfo assemblyInfo, MethodUniqueSignature signature) => new CallInfo(0, null, assemblyInfo, signature, true, new List <MethodUniqueSignature>(0));
private bool Equals(MethodUniqueSignature other) { return(string.Equals(fullName, other.fullName)); }
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); }
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); }