Analyzer.cs 7.2 KB

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