Analyzer.cs 7.9 KB

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