Analyzer.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. using dnlib.DotNet;
  2. using HybridCLR.Editor.Meta;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using UnityEngine;
  9. namespace HybridCLR.Editor.MethodBridge
  10. {
  11. public class Analyzer
  12. {
  13. public class Options
  14. {
  15. public AssemblyReferenceDeepCollector Collector { get; set; }
  16. public int MaxIterationCount { get; set; }
  17. }
  18. private readonly int _maxInterationCount;
  19. private readonly AssemblyReferenceDeepCollector _assemblyCollector;
  20. private readonly object _lock = new object();
  21. private readonly List<TypeDef> _typeDefs = new List<TypeDef>();
  22. private readonly HashSet<GenericClass> _genericTypes = new HashSet<GenericClass>();
  23. private readonly HashSet<GenericMethod> _genericMethods = new HashSet<GenericMethod>();
  24. private List<GenericMethod> _processingMethods = new List<GenericMethod>();
  25. private List<GenericMethod> _newMethods = new List<GenericMethod>();
  26. public IReadOnlyList<TypeDef> TypeDefs => _typeDefs;
  27. public IReadOnlyCollection<GenericClass> GenericTypes => _genericTypes;
  28. public IReadOnlyCollection<GenericMethod> GenericMethods => _genericMethods;
  29. private readonly MethodReferenceAnalyzer _methodReferenceAnalyzer;
  30. public Analyzer(Options options)
  31. {
  32. _maxInterationCount = options.MaxIterationCount;
  33. _assemblyCollector = options.Collector;
  34. _methodReferenceAnalyzer = new MethodReferenceAnalyzer(this.OnNewMethod);
  35. }
  36. private void TryAddAndWalkGenericType(GenericClass gc)
  37. {
  38. if (gc == null)
  39. {
  40. return;
  41. }
  42. lock(_lock)
  43. {
  44. gc = StandardizeClass(gc);
  45. if (_genericTypes.Add(gc))
  46. {
  47. WalkType(gc);
  48. }
  49. }
  50. }
  51. private GenericClass StandardizeClass(GenericClass gc)
  52. {
  53. TypeDef typeDef = gc.Type;
  54. ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes;
  55. List<TypeSig> klassGenericParams = gc.KlassInst != null ? MetaUtil.ToShareTypeSigs(corLibTypes, gc.KlassInst) : (typeDef.GenericParameters.Count > 0 ? MetaUtil.CreateDefaultGenericParams(typeDef.Module, typeDef.GenericParameters.Count) : null);
  56. return new GenericClass(typeDef, klassGenericParams);
  57. }
  58. private GenericMethod StandardizeMethod(GenericMethod gm)
  59. {
  60. TypeDef typeDef = gm.Method.DeclaringType;
  61. ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes;
  62. List<TypeSig> klassGenericParams = gm.KlassInst != null ? MetaUtil.ToShareTypeSigs(corLibTypes, gm.KlassInst) : (typeDef.GenericParameters.Count > 0 ? MetaUtil.CreateDefaultGenericParams(typeDef.Module, typeDef.GenericParameters.Count) : null);
  63. List<TypeSig> methodGenericParams = gm.MethodInst != null ? MetaUtil.ToShareTypeSigs(corLibTypes, gm.MethodInst) : (gm.Method.GenericParameters.Count > 0 ? MetaUtil.CreateDefaultGenericParams(typeDef.Module, gm.Method.GenericParameters.Count) : null);
  64. return new GenericMethod(gm.Method, klassGenericParams, methodGenericParams);
  65. }
  66. private void OnNewMethod(MethodDef methodDef, List<TypeSig> klassGenericInst, List<TypeSig> methodGenericInst, GenericMethod method)
  67. {
  68. lock(_lock)
  69. {
  70. method = StandardizeMethod(method);
  71. if (_genericMethods.Add(method))
  72. {
  73. _newMethods.Add(method);
  74. }
  75. if (method.KlassInst != null)
  76. {
  77. TryAddAndWalkGenericType(new GenericClass(method.Method.DeclaringType, method.KlassInst));
  78. }
  79. }
  80. }
  81. private void WalkType(GenericClass gc)
  82. {
  83. //Debug.Log($"typespec:{sig} {sig.GenericType} {sig.GenericType.TypeDefOrRef.ResolveTypeDef()}");
  84. //Debug.Log($"== walk generic type:{new GenericInstSig(gc.Type.ToTypeSig().ToClassOrValueTypeSig(), gc.KlassInst)}");
  85. ITypeDefOrRef baseType = gc.Type.BaseType;
  86. if (baseType != null && baseType.TryGetGenericInstSig() != null)
  87. {
  88. GenericClass parentType = GenericClass.ResolveClass((TypeSpec)baseType, new GenericArgumentContext(gc.KlassInst, null));
  89. TryAddAndWalkGenericType(parentType);
  90. }
  91. foreach (var method in gc.Type.Methods)
  92. {
  93. var gm = StandardizeMethod(new GenericMethod(method, gc.KlassInst, null));
  94. //Debug.Log($"add method:{gm.Method} {gm.KlassInst}");
  95. if (_genericMethods.Add(gm))
  96. {
  97. if (method.HasBody && method.Body.Instructions != null)
  98. {
  99. _newMethods.Add(gm);
  100. }
  101. }
  102. }
  103. }
  104. private void WalkType(TypeDef typeDef)
  105. {
  106. _typeDefs.Add(typeDef);
  107. ITypeDefOrRef baseType = typeDef.BaseType;
  108. if (baseType != null && baseType.TryGetGenericInstSig() != null)
  109. {
  110. GenericClass gc = GenericClass.ResolveClass((TypeSpec)baseType, null);
  111. TryAddAndWalkGenericType(gc);
  112. }
  113. foreach (var method in typeDef.Methods)
  114. {
  115. // 对于带泛型的参数,统一泛型共享为object
  116. var gm = StandardizeMethod(new GenericMethod(method, null, null));
  117. _genericMethods.Add(gm);
  118. }
  119. }
  120. private void Prepare()
  121. {
  122. // 将所有非泛型函数全部加入函数列表,同时立马walk这些method。
  123. // 后续迭代中将只遍历MethodSpec
  124. foreach (var ass in _assemblyCollector.GetLoadedModules())
  125. {
  126. foreach (TypeDef typeDef in ass.GetTypes())
  127. {
  128. WalkType(typeDef);
  129. }
  130. for (uint rid = 1, n = ass.Metadata.TablesStream.TypeSpecTable.Rows; rid <= n; rid++)
  131. {
  132. var ts = ass.ResolveTypeSpec(rid);
  133. var cs = GenericClass.ResolveClass(ts, null);
  134. if (cs != null)
  135. {
  136. TryAddAndWalkGenericType(cs);
  137. }
  138. }
  139. for (uint rid = 1, n = ass.Metadata.TablesStream.MethodSpecTable.Rows; rid <= n; rid++)
  140. {
  141. var ms = ass.ResolveMethodSpec(rid);
  142. var gm = GenericMethod.ResolveMethod(ms, null)?.ToGenericShare();
  143. if (gm == null)
  144. {
  145. continue;
  146. }
  147. gm = StandardizeMethod(gm);
  148. if (_genericMethods.Add(gm))
  149. {
  150. _newMethods.Add(gm);
  151. }
  152. }
  153. }
  154. Debug.Log($"PostPrepare allMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}");
  155. }
  156. private void RecursiveCollect()
  157. {
  158. for (int i = 0; i < _maxInterationCount && _newMethods.Count > 0; i++)
  159. {
  160. var temp = _processingMethods;
  161. _processingMethods = _newMethods;
  162. _newMethods = temp;
  163. _newMethods.Clear();
  164. Task.WaitAll(_processingMethods.Select(method => Task.Run(() =>
  165. {
  166. _methodReferenceAnalyzer.WalkMethod(method.Method, method.KlassInst, method.MethodInst);
  167. })).ToArray());
  168. Debug.Log($"iteration:[{i}] genericClass:{_genericTypes.Count} genericMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}");
  169. }
  170. }
  171. public void Run()
  172. {
  173. Prepare();
  174. RecursiveCollect();
  175. }
  176. }
  177. }